Ubuntu14.04上でglibcをbuildしてリンクする
glibc内のソースをいじりたかったのでその前準備にglibcソースからビルドしてコードにリンクするまでの手順をメモ
環境
vagrant@vagrant-ubuntu-trusty-64:~/libc$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.5 LTS Release: 14.04 Codename: trusty
vagrant上で動かしてます
glibcの取得
$ sudo apt-get update $ mkdir -p ~/libc/build # libcのビルド用ディレクトリを作成します。build用ディレクトリを分けないとconfigure時に怒られるため $ cd ~/libc $ sudo apt-get install -y dpkg-dev $ sudo apt-get source libc6
終わったときの~/libc
の中はこんな感じのはず
vagrant@vagrant-ubuntu-trusty-64:~/libc$ ll total 13360 drwxrwxr-x 4 vagrant vagrant 4096 Oct 17 09:21 ./ drwxr-xr-x 6 vagrant vagrant 4096 Oct 17 09:54 ../ drwxrwxr-x 60 vagrant vagrant 4096 Oct 17 09:42 build/ drwxr-xr-x 73 root root 4096 Oct 17 09:14 eglibc-2.19/ -rw-r--r-- 1 root root 1043124 Jan 17 2018 eglibc_2.19-0ubuntu6.14.debian.tar.xz -rw-r--r-- 1 root root 7195 Jan 17 2018 eglibc_2.19-0ubuntu6.14.dsc -rw-r--r-- 1 root root 12610800 Feb 21 2014 eglibc_2.19.orig.tar.xz
configureとmake
最終的に吐き出すディレクトリは /usr/eglibc-2.19
にします。これは好きなディレクトリで大丈夫です
$ sudo mkdir -p /usr/eglibc-2.19 $ ~/libc/build $ ../eglibc-2.19/configure --prefix=/usr/eglibc-2.19 --enable-add-ons=nptl --enable-all-warnings $ sudo make # かなり時間がかかります $ sudo make install
以上で /usr/eglibc-2.19
以下にビルドされたファイル群が存在すれば大丈夫です
テスト用のコードとビルド
試しに以下のコードを書いてコンパイルしてみます
#include <stdio.h> int main() { printf("hello\n"); exit(0); }
Makefileはこんな感じ
CC=gcc CFLAGS = -nostdinc -I/usr/eglibc-2.19/include -I/usr/lib/gcc/x86_64-linux-gnu/4.8/include LDFLAGS = -Wl,-rpath=/usr/eglibc-2.19/lib TARGET = test.exe OBJECTS = test.o all: $(TARGET) $(TARGET):$(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o $(TARGET) .c.o: $(CC) $(CFLAGS) -c -o $@ $< clean: rm -f *.o $(TARGET)
CFLAGSとLDFLAGSに指定しているパスは各自がconfigure時に設定したprefixパスに合わせてください
makeして ldd
コマンドで指定したglibcにリンクできているか確認します
vagrant@vagrant-ubuntu-trusty-64:~$ ldd test.exe linux-vdso.so.1 => (0x00007ffe58f8d000) libc.so.6 => /usr/eglibc-2.19/lib/libc.so.6 (0x00007f34057a3000) /lib64/ld-linux-x86-64.so.2 (0x00007f3405b50000)
libc.so.6の部分が上のように指定したlibcになっていればokです
Gormにおける多層外部キーの定義の仕方とコードの書き方
最近バイトの方でgormの振る舞いとデータベースのテーブル構造のことでハマったのでそれについてメモっておきます
テーブル構造とgoのモデル
最初にあったテーブル構造は上の図のような感じ。
今回は例として地域、地域に存在する書店たち、書店の持つ本をマッピングしてみました。
地域と書店の関係はhas many、書店と本もhas manyとなっています。
これをgoのコードにmodelとして書き出すと以下のような感じになりました。
package main import "time" type Region struct { ID int Shops []Shop `gorm:"foreignkey:ID"` CreatedAt time.Time UpdatedAt time.Time } type Shop struct { ID int Name string Books []Book `gorm:"foreignkey:ShopID"` CreatedAt time.Time UpdatedAt time.Time } type Book struct { ID int ShopID int Name string Price int CreatedAt time.Time UpdatedAt time.Time }
テーブル作成のsqlは次のようになります
CREATE TABLE IF NOT EXISTS region ( id serial NOT NULL, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , CONSTRAINT region_id PRIMARY KEY ( id ) ); CREATE TABLE IF NOT EXISTS shop ( id serial NOT NULL, name varchar(255) NOT NULL, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , CONSTRAINT shop_id PRIMARY KEY ( id ), CONSTRAINT shop_id_region_id_foreign FOREIGN KEY ( id ) REFERENCES region( id ) ON UPDATE NO ACTION ON DELETE NO ACTION ); CREATE TABLE IF NOT EXISTS book ( id serial NOT NULL, shop_id bigint(20) unsigned NOT NULL, name varchar(255) NOT NULL, price int NOT NULL, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , CONSTRAINT book_id PRIMARY KEY ( id ), CONSTRAINT book_shop_id_shop_id_foreign FOREIGN KEY ( shop_id ) REFERENCES shop( id ) ON UPDATE NO ACTION ON DELETE NO ACTION );
shopは自身のIDは外部キーでregionのidと紐づけています bookはshop idを外部キーでshopのidと紐づけています
gormでinsertする
これらのデータ構造はgormにおいて次のように一括でcreateすることができます。
r := Region{ Shops: []Shop{ Shop{ Name: "shop1", Books: []Book{ Book{ Name: "book1", Price: 100, }, Book{ Name: "book2", Price: 200, }, }, }, }, } if err := mysql.Create(&r).Error; err != nil { log.Fatal(err) }
gormがタグに紐づけた外部キーの情報からよしなに親をinsertした後、確定したIDの情報を用いて, 子のテーブルにまでinsertしてくれるのです。
しかし、このデータ構造の場合次のようなエラーが起こります。
/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:27:44] [3.76ms] INSERT INTO `region` (`created_at`,`updated_at`) VALUES ('2018-08-25 13:27:44','2018-08-25 13:27:44') [1 rows affected or returned ] (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:27:44] [10.12ms] UPDATE `shop` SET `name` = 'shop1', `created_at` = '0001-01-01 00:00:00', `updated_at` = '2018-08-25 13:27:44' WHERE `shop`.`id` = '2' [0 rows affected or returned ] (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:27:44] Error 1452: Cannot add or update a child row: a foreign key constraint fails (`debug`.`book`, CONSTRAINT `book_shop_id_shop_id_foreign` FOREIGN KEY (`shop_id`) REFERENCES `shop` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:27:44] [5.02ms] INSERT INTO `book` (`shop_id`,`name`,`price`,`created_at`,`updated_at`) VALUES ('2','book1','100','2018-08-25 13:27:44','2018-08-25 13:27:44') [0 rows affected or returned ] (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:27:44] Error 1452: Cannot add or update a child row: a foreign key constraint fails (`debug`.`book`, CONSTRAINT `book_shop_id_shop_id_foreign` FOREIGN KEY (`shop_id`) REFERENCES `shop` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:27:44] Error 1452: Cannot add or update a child row: a foreign key constraint fails (`debug`.`book`, CONSTRAINT `book_shop_id_shop_id_foreign` FOREIGN KEY (`shop_id`) REFERENCES `shop` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:27:44] Error 1452: Cannot add or update a child row: a foreign key constraint fails (`debug`.`book`, CONSTRAINT `book_shop_id_shop_id_foreign` FOREIGN KEY (`shop_id`) REFERENCES `shop` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) 2018/08/25 13:27:44 Error 1452: Cannot add or update a child row: a foreign key constraint fails (`debug`.`book`, CONSTRAINT `book_shop_id_shop_id_foreign` FOREIGN KEY (`shop_id`) REFERENCES `shop` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
エラーの内容はupdateが走り, それはconstraintに違反しているというものでした(多分)
これの原因はShopの主キーであり、外部キーでもあるIDとRegionの主キーを紐づけていることに起因すると思われます。
正しいテーブル構造
なので、ちゃんとしたテーブル構造は次のようになります
sqlはこんな感じ
CREATE TABLE IF NOT EXISTS region ( id serial NOT NULL, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , CONSTRAINT region_id PRIMARY KEY ( id ) ); CREATE TABLE IF NOT EXISTS shop ( id serial NOT NULL, region_id bigint(20) unsigned NOT NULL, name varchar(255) NOT NULL, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , CONSTRAINT shop_id PRIMARY KEY ( id ), CONSTRAINT shop_region_id_region_id_foreign FOREIGN KEY ( region_id ) REFERENCES region( id ) ON UPDATE NO ACTION ON DELETE NO ACTION ); CREATE TABLE IF NOT EXISTS book ( id serial NOT NULL, shop_id bigint(20) unsigned NOT NULL, name varchar(255) NOT NULL, price int NOT NULL, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , CONSTRAINT book_id PRIMARY KEY ( id ), CONSTRAINT book_shop_id_shop_id_foreign FOREIGN KEY ( shop_id ) REFERENCES shop( id ) ON UPDATE NO ACTION ON DELETE NO ACTION );
goのmodelのコードはこんな感じ
type Region struct { ID int Shops []Shop `gorm:"foreginkey:RegionID"` CreatedAt time.Time UpdatedAt time.Time } type Shop struct { ID int RegionID int Name string Books []Book `gorm:"foreignkey:ShopID"` CreatedAt time.Time UpdatedAt time.Time } type Book struct { ID int ShopID int Name string Price int CreatedAt time.Time UpdatedAt time.Time }
ShopにRegionIDという外部キー用のカラムを追加しています。
これで先程のcreateを実行してみると
(/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:18:15] [2.14ms] INSERT INTO `region` (`created_at`,`updated_at`) VALUES ('2018-08-25 13:18:15','2018-08-25 13:18:15') [1 rows affected or returned ] (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:18:15] [6.41ms] INSERT INTO `shop` (`region_id`,`name`,`created_at`,`updated_at`) VALUES ('2','shop1','2018-08-25 13:18:15','2018-08-25 13:18:15') [1 rows affected or returned ] (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:18:15] [1.57ms] INSERT INTO `book` (`shop_id`,`name`,`price`,`created_at`,`updated_at`) VALUES ('1','book1','100','2018-08-25 13:18:15','2018-08-25 13:18:15') [1 rows affected or returned ] (/Users/bo0km4n/go/src/github.com/Bo0km4n/dev/mysql_gorm_association/main.go:32) [2018-08-25 13:18:15] [3.31ms] INSERT INTO `book` (`shop_id`,`name`,`price`,`created_at`,`updated_at`) VALUES ('1','book2','200','2018-08-25 13:18:15','2018-08-25 13:18:15') [1 rows affected or returned ] main.Region{ ID: 2, Shops: []main.Shop{ main.Shop{ ID: 1, RegionID: 2, Name: "shop1", Books: []main.Book{ main.Book{ ID: 1, ShopID: 1, Name: "book1", Price: 100, CreatedAt: 2018-08-25 13:18:15 Local, UpdatedAt: 2018-08-25 13:18:15 Local, }, main.Book{ ID: 2, ShopID: 1, Name: "book2", Price: 200, CreatedAt: 2018-08-25 13:18:15 Local, UpdatedAt: 2018-08-25 13:18:15 Local, }, }, CreatedAt: 2018-08-25 13:18:15 Local, UpdatedAt: 2018-08-25 13:18:15 Local, }, }, CreatedAt: 2018-08-25 13:18:15 Local, UpdatedAt: 2018-08-25 13:18:15 Local, }
ちゃんと一括でinsertされているのがわかりました!
まとめ
そもそも最初失敗のケースでハマっていたのは親子関係のみの場合はうまく行っていたからです。親子孫のように増えると先程のようなエラーが出て四苦八苦していました。
ちなみに例に上げた親子の関係は1to1でもエラーは起きます。
テーブルの主キーと他のテーブルの主キーを外部キーとして紐付けるのは割とやりがちなケースな気がしますが、しっかり別カラムで紐づけた方が安全な気はします。
今回のサンプルコードは以下に載せてあります
2018上半期院の授業振り返り
お久しぶりです。 今回は僕が上半期に芝浦工業大学大学院電気電子情報工学専攻で取った授業についてレビューというか感想的なものを書いていこうと思います。
後輩の方々に向けての参考になれば幸いです。
構成はこんな感じで書いていきます。
- 授業名
- 概要
- よかったところ
- 悪かったところ
- オススメ度
オススメ度は4段階評価です。
分散システム特論
概要
広域ネットワークを前提とした分散システムを実現するために必要な知識や概念を体系的に学び、実装を通して技術的概要を理解する。 実装に関しては主に5つの課題があります。
- TCP/IPスタックの実装
- プロセス間通信の演習(pthread, fork)
- javaとC間のRPC 実装(javaのオブジェクトシリアライザ、デシリアライザの実装)
- 名前付け演習(Linux V6のファイルシステム実装)
- 同期演習(Lamportの全順序アルゴリズムの実装)
よかったところ
ファイルシステムやjavaのシリアライズについての仕様について実装を通して学べる。実装する言語を自分で選べる課題も多くて助かりました。ゴリゴリ実装する授業なので個人的に非常に楽しかったです。
悪かったところ
火曜1限というとこ
オススメ度
- 3 プログラミング好きな人なら取るべき。そうでないならお勧めしない。
自然言語処理システム特論
概要
自然言語処理システムの基礎となる理論的モデルと処理技術を理解し、 システム作成実験や論文輪講を通じてその実現手法と応用事例について学ぶ。 この授業は主に二つのフェーズに分かれます。
僕のグループは単語の類似度計算というテーマでword2vecなどを用いず、共起度とSVD演算を用いて意味の類似度を演算するシステムを実装しました。大変でした。
輪講はこちら
http://www.aclweb.org/anthology/W16-3641
の論文を読みましたが、これは次の研究へつなげるための前座的論文なので実装的なお話は一切ありませんでした。
よかったところ
自然言語処理における、意味解析、構文解析、応用としてのシステムに関しての知識を一通り学べるのはよかったです。
悪かったところ
課題が割とヘヴィということ。二単位でやる感じではない。 グループでの作業分担がしっかりできる人は大丈夫なはず。
オススメ度
- 2 微妙なラインです。 この時限に他に取りたいのがあるならそちらを取るべきかもしれない。 ただ、最近は自然言語処理と機械学習はほぼセット扱いでバズワードなのでやっといて損はないはず。 何にしても他の授業とかと比較してみるのがお勧め
基盤システム特論
実践的な研究開発を通じて、分散システムプラットフォームの本質である並行性、並列性、信頼性についての理解を深める。 この授業は最初は分散システム特論と同じ教科書を使った輪講、その後にグループでのシステム開発になります。 開発するシステムは基本的にIoTデバイス、要はロボットとかセンサが一つ絡んであることが必須条件でそれ以外は特にありません。
よかったところ
自分の実装力を確認できる。
悪かったところ
一言でいうと概要詐欺だということ。 僕がこの授業に最初に想像していたのは 「分散システムを実装してスケールアウトできるか、信頼性などはあるかといった評価をする」ものだと思っていました。 それが蓋をあけてみれば、「どっかの学会に論文出せるようなアイディア重視のシステム作って論文書いて!!」と教授がひたすらしつこく要求してくるものでした。
要は分散システムである必要とかなくてシステムのアイディアが一番重要視されてスケールなんかしなくてもいいんです。 分散システムどこいった。
僕が一生懸命draw.ioで作った下の図は構想発表などでも特に触れられず、他の班の「脳波から感情を推定する」「植物の感情を推定する」とかに教授は嬉々としていました。 アイディアはすごいけどそれ分散システムの体なしてなくない?って感じでした。
なお他の班の多くは一切並列性、並行性、信頼性などに関しては触れていませんでした。システム自体もセンサとサーバ一対一で繋がってるだけ。 なんだこれ。 なんだか必死にスケールできるように!ってアーキテクチャを考えた僕が唐突に恥ずかしくなりました。
最初からそういう授業だとわかっていればいいですが、これに関してはあまりにもシラバスで言及がなさすぎます。 あと一つ個人的に言うならインプットが一切なかったということです。
授業なので何かしら新しい知識や技術を期待していましたが全くありませんでした。輪講は分散システム特論と被っているので全く意味がありません。 ただオレオレシステムを実装するだけです。
加えて、授業終了後の夏休み後も論文を学会に提出する人(一応希望制)は引き続き評価とか執筆に勤しみます。
オススメ度
- -255 悪いところばかり書いたのでお分かりかと思いますが、全くお勧めしません。 時間を無駄にするだけなので他の授業を取ることをお勧めします。 唯一お勧めできるのは「なんかようわからんアイディアもってるけどこれで単位が欲しい!」という人だけです。
データ工学特論
概要
多くのデータから有意な情報を抽出するデータマイニング手法のうち代表的なものを理解し、輪講を通して、基礎的な知識の習得と最新の研究動向の把握を行う。 この授業は先生の講義とグループでの論文輪講が主です。
講義では以下のような手法に関して詳しく解説されます
- アソシエーション分析、記憶ベース理論
- クラスタリング(k近傍とかその他もろもろ)、遺伝的アルゴリズム
- 決定木、ネットワーク分析
- ニューラルネットワーク
- テキストマイニング
輪講で僕のグループが読んだ論文はこちらです。
http://db-event.jpn.org/deim2017/papers/64.pdf
セキュリティ系のクラスタリング手法を絡めた研究は実用化が結構大変そうなイメージですね。
よかったところ
各手法に関して基礎的な数学の話も含めて、応用先などを丁寧に解説してくれて非常にわかりやすい授業でした。 必然的に機械学習の手法も多く絡んでくるので聞いてて楽しかったです。
悪かったところ
特にないです。
オススメ度
ソフトウェア構成特論
概要
単純な型システムをもつプログラミング言語を定義し、それについての操作的意味や、記述された式に対して型についての整合性などについての理解を促す。
この授業は
の本を噛み砕いて説明、問題の演習を行ってくれています。 この授業を通じて静的型付け言語に対して基礎的な理解を深めることが目的となっています。
よかったところ
書籍をよりわかりやすく、演習問題を通じて丁寧に解説してくれています。 型付きラムダ計算などを代数学?てきに証明するっていうのは解いてて面白かったです。
わるかったところ
特になし
オススメ度
- 3 4にしたかったんですが分野があまりにもニッチなので一応3にしておきました。 ただプログラミング言語に対してもっと理解を深めたい人にはすごくお勧めできる授業です。
まとめ
以上が僕が今期にとった授業についてです。 とにかく基盤システム特論だけはオススメしません。
他の授業は結構身になるものが多かったので良かったです。 この記事が少しでも誰かの参考になればうれしいです。
GAEにデプロイするとき今のバージョンのzapは使っちゃだめ
GAEでgolangのwebサービスをデプロイしようとしたとき
unique id発行のために上のライブラリを使っていたんですが、内部でzapを使っていました。
zapは以下のようにgo1.9から追加されたtype aliasを使っています。
package zap import ( "fmt" "math" "time" "go.uber.org/zap/zapcore" ) // Field is an alias for Field. Aliasing this type dramatically // improves the navigability of this package's API documentation. type Field = zapcore.Field // Skip constructs a no-op field, which is often useful when handling invalid // inputs in other Field constructors. func Skip() Field { return Field{Type: zapcore.SkipType} }
この場合、GAEにデプロイするときに次のようなエラーでこけます。
File upload done. Updating service [default]...failed. ERROR: (gcloud.app.deploy) Error Response: [9] Deployment contains files that cannot be compiled: Compile failed: /work_dir/go.uber.org/zap/field.go:33: syntax error: unexpected = in type declaration 2018/05/24 22:16:54 go-app-builder: build timing: 72×compile (9m48.835s total), 0×link (0s total) 2018/05/24 22:16:54 go-app-builder: failed running compile: exit status 2
GAEのruntimeが1.8までしかまだ対応してないからですね。
というわけでzap使いたい場合はGAEが1.9に上がるまで待ちましょう。 今回はkatsubushiの代わりにxidを使うことにしました。
自作OS入門の環境をOS Xで整える
動機
「30日でできる!OS自作入門」を読み実装しようと思ったところ、環境がwindows。おまけにアセンブラやビルド環境がWindows故、そのまま流用できませんでした。
そこで少し色々調べた結果、http://bttb.s1.valueserver.jp/wordpress/blog/2017/11/14/make-os1/ この方のブログが大変シンプルに纏まっており参考にさせていただくことにしました。 このブログの環境はLinuxなので大体は流用することができます。
1日、2日目の内容はアセンブラオンリーなので特に問題はなかったのですが3日目以降はC言語とアセンブラをリンクしてビルドする必要がでてきます。 この際、OS Xだと少々一筋縄ではいかない問題がでてきます。
それがgccとldリンカです。OS Xに標準で入っているのは恐らくXcode-command-line-toolsを入れた時に一緒に入るgccです。
gccは別にいいのですがldはGNU ldではないため、リンカスクリプトを指定する-T
オプションがありません。
そこで、本はi386をターゲットにビルドしているのでi386のクロスコンパイル環境を構築することにしました。
以下にその際の手順を示します。
QEMU
brew install qemu
nasm
brew install nasm
i386-elf-gcc, gnu ld
ここからが少し長いです。 基本的に同じコマンドを実行すれば大丈夫なはずです(2018-5現在)
brew install gcc6 export CC=/usr/local/Cellar/gcc@6/6.4.0_2/bin/gcc-6 # ↑の手順でinstallしたGCCのパス export LD=/usr/local/bin/gcc@6/6.4.0_2/bin/gcc-6 export PREFIX="/usr/local/i386elfgcc" export TARGET=i386-elf export PATH="$PREFIX/bin:$PATH" # binutilsのインストール mkdir /tmp/src cd /tmp/src curl -O http://ftp.gnu.org/gnu/binutils/binutils-2.28.tar.gz tar xf binutils-2.28.tar.gz mkdir binutils-build cd binutils-build ../binutils-2.28/configure --target=$TARGET --enable-interwork --enable-multilib --disable-nls --disable-werror --prefix=$PREFIX 2>&1 | tee configure.log sudo make all install 2>&1 | tee make.log # libiconv最新版をインストールする cd /tmp/src curl -O https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz tar xf libiconv-1.15.tar.g cd libiconv-1.15 ./configure -prefix=/usr/local make make install # クロスコンパイラなGCCをビルド cd /tmp/src curl -O https://ftp.gnu.org/gnu/gcc/gcc-6.4.0/gcc-6.4.0.tar.gz tar xf gcc-6.4.0.tar.gz mkdir gcc-build cd gcc-build ../gcc-6.4.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --disable-libssp --enable-languages=c --without-headers --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpfr=/usr/local --with-libiconv-prefix=/usr/local make all-gcc make all-target-libgcc sudo make install-gcc sudo make install-target-libgcc
最終的な環境
- 開発環境: OS X HighSierra
- エミュ: QEMU emulator version 2.11.0 Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers
- アセンブラ: nasm
- Cコンパイラ: gcc - i386-elf-gcc (base gcc ver6)
- リンカ: ld - gnu ld
テスト
以上の環境構築が終了した場合、
の day4/harib01j
内で make run
をするとそれっぽいosの画面がqemuで開くはずです。
brew updateしたらなんかvimが動かなくなった
ある日 brew update
したらvimが
dyld: Library not loaded: /usr/local/opt/lua/lib/liblua.5.2.dylib Referenced from: /usr/local/bin/./vim Reason: image not found
/usr/local/opt/lua/lib/liblua.5.2.dylib がないと言われた。実際にパスに移動するとなかった。
ということで
bilibili-mac-client/liblua.5.2.dylib at master · typcn/bilibili-mac-client · GitHub からファイルをダウンロードして /usr/local/opt/lua/lib
にmvしたら動いた。
Contikiにおけるファイル分割してコンパイルの仕方とPROCESSによる並列実行
卒業研究で使ってるWSN用のOS、というより超巨大ライブラリのContikiというものについてメモしておきます。
Why
そもそも日本語のドキュメントは勿論、英語でのドキュメントもサンプルを動かしただけとかばっかで深いところに突っ込むにはソースコード読むしかないという現状だったのでもし他にこの分野に手を付ける人がいたらその助けになればいいなという思いと、自分で忘れないようにするために書いておきます。
Contikiとは
WSN用のOSです。マルチスレッドを標準でサポートしています。何を当たり前のことをと思うかもしれませんが無線センサネットワークとかの界隈ではリソースの都合上結構すごいことだったりする。
このOSで動くプログラムはC言語で書けます。これまた「今時C〜?古くない〜?」と言われそうですが、結構有名なWSN用のOS、TinyOSとかはnesCとかいうドキュメントは英語の本一冊のみという魔の言語で書かなきゃいけなかったりするので恵まれている方です。
あとCoojaというGUIシミュレータが付属しているので基本的には書いたプログラムをこのシミュレータでデバッグしながら開発することができます。 とりあえずContikiで動かすことができるもっとも簡単なプログラムを示します。
#include "contiki.h" #include "stdio.h" /*---------------------------------------------------------------------------*/ PROCESS(hello_world_process, "Hello world process"); AUTOSTART_PROCESSE(&hello_world_process); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(hello_world_process, ev, data) { PROCESS_BEGIN(); printf("Hello, Cooja\n"); PROCESS_END(); } /*---------------------------------------------------------------------------*/
お決まりのHello world!ですがこれだけでも結構なことをしています。 一行ずつ説明していきます。
PROCESS(プロセス名, プロセス呼び出し時に出力する文字列)
これは
hello_world_process
という名前のプロセス構造体を定義しています。第二引数は呼び出し時に標準出力に出力する文字列です。AUTOSTART_PROCESS(プロセス構造体のアドレス)
センサー起動時にこのプロセスを自動的に起動します。これがないとセンサを起動しても何も起きません。 プロセスをコード上で任意に起動することもできますがそれは後述します。
PROCESS_THREAD(プロセス構造体, イベント, データ) { ... }
プロセスの実際の処理を記述する関数です。このPROCESS_THREADは他のPROCESS_THREADとは並列に処理されます。 イベントはセンサ本体のボタンなどが押されたときのシグナルを判定する時に使用します。 データはコード上でプロセスを起動した時に任意のデータポインタを渡すことができます。
PROCESS_BEGIN() ... PROCESS_END()
この間に書かれた処理が実行されます。 PROCESS_END()が実行されても完全にプログラムの実行が終わったわけではなく, バックグラウンドではセンサ毎に定義されているOSプログラムが存在して, 低電力モードなどへの移行を行っています。あくまでここに定義されたプロセスをベースとなるOS上で実行しているイメージです。
コンパイルの仕様
センサで動かすプログラムをContikiがコンパイルする際には全てMakefileでセンサーごとに独自のバイナリにコンパイルしていきます。
例えば、上の hello_world.c
をコンパイルする際にはMakefileはこのようになります。
CONTIKI_PROJECT = hello-world all: $(CONTIKI_PROJECT) CONTIKI = ../.. include $(CONTIKI)/Makefile.include
makeする際には make TARGET=...
でTARGETに動かしたいセンサを指定します。
あとはhello-world.cにガリガリ書いていけばいいのですがある程度コードの規模が大きくなると1ファイルで管理するのは非常に面倒でした。 そこで他のヘッダファイルに定義した関数を別のcファイルで実装し、それを呼び出す場合は
Makefileに PROJECT_SOURCEFILES += hoge.c fuga.c
と定義します。
この時のディレクトリ構成はこんな感じです。
. ├── Makefile ├── README.md ├── fuga.c ├── fuga.h ├── hello-world.c ├── hoge.c ├── hoge.h ├── symbols.c └── symbols.h
この時, fuga.c hoge.c
を別階層のディレクトに配置すると, コンパイルしたファイルを参照できなくなりエラーが起こります。
別プロセスの呼び出し
では試しに hoge.h
にhoge_processを定義し, hoge.c
に実装し, hello-world.c
でボタンが押された時に hoge_process
を呼び出す処理を書いてみます
hoge.h
#ifndef _HOGE_H_ #define _HOGE_H_ void start_hoge_process(); #endif
hoge.c
#include "contiki.h" #include "stdio.h" PROCESS(hoge_process, "hoge process"); PROCESS_THREAD(hoge_process, ev, data) { PROCESS_BEGIN(); printf("hoge %d\n", data); PROCESS_END(); } void start_hoge_process(void) { process_start(&hoge_process, (void *)100); }
hello-world.c
#include "contiki.h" #include "dev/button-sensor.h" #include "dev/leds.h" #include <stdio.h> /* For printf() */ /*---------------------------------------------------------------------------*/ PROCESS(hello_world_process, "Hello world process"); AUTOSTART_PROCESSES(&hello_world_process); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(hello_world_process, ev, data) { PROCESS_BEGIN(); SENSORS_ACTIVATE(button_sensor); printf("Hello, Cooja\n"); while(1) { PROCESS_WAIT_EVENT_UNTIL(ev == sensors_event && data == &button_sensor); start_hoge_process(); } PROCESS_END(); }
これによって hello-word.c
をコンパイルしてcoojaシミュレータで起動(センサーの種別は問いません)し、
センサのボタンをクリックするとログに hoge 100
と出力されるはずです。
ContikiのMakefileには独自のフラグが多くあるのでまた自分が何か見つけたらメモしておこうと思います。 私のContikiで開発中のリポジトリはこちらです。興味があったらContikiでプログラミングしてみてください。 そして私に知見をください。
contiki本体のリポジトリはこちらになります
wikiも一応あるにはありますが大体動かしつつソース読むのが手っ取り早いです。
それにしてもWSNの具体的なユースケースや規模がググっても全然出てこないので評価の仕様策定に苦戦中です。 辛い