Neunomizuの日記

俺だけが俺だけじゃない

競プロ用にMakefileを作った

競プロ用にMakefileを作った

モジュール化が大事

プログラマーたるものできる限りいらない作業を減らして効率化したいですよね?

今回は競プロでコンパイラ(C++を使っているので)する際にもう少し簡単にできるようにMakefileを作ってみました.

Makefileとは?

Wikipediaによれば,

make(メイク)は、プログラムのビルド作業を自動化するツール。コンパイル、リンク、インストール等のルールを記述したテキストファイル (makefile) に従って、これらの作業を自動的に行う。

だそうです.簡単に言えばterminal上でmakeと打つと色々勝手にしてくれるのだそうです.

実際に書いたファイル

以下が実際に書いたMakefileです.

参考にしたのはこのサイトです. この改変したコードに使って,Makefileに対する理解を深めたいと思います.

CXX := g++ # コンパイラをg++に指定
CXXFLAGS := -Wall -o # コンパイルオプションを指定
SUFFIXES := .cpp # ソースの拡張子を指定
SOURCES = $(wildcard *$(SUFFIXES)) # コンパイルするソースの指定
TARGETS = $(SOURCES: .cpp=) # 全てのファイルでコンパイルを実行

.PHONY:all # 仮想ファイルallを作る
all: $(TARGETS) # 仮想ファイルを作り,TARGETSを実行する
# $@: ターゲットファイル名
# $<: 最初に依存するファイル名
.cpp:
    $(CXX) $(CXXFLAGS) $@ $< # コンパイルオプションを使って,コンパイルを実行

変数の宣言部分の解説

これを見ただけで理解できる人はUNIXコマンドに慣れている人だと思います.

まず,この部分から

CXX := g++ # コンパイラをg++に指定
CXXFLAGS := -Wall -o # コンパイルオプションを指定
SUFFIXES := .cpp # ソースの拡張子を指定
SOURCES = $(wildcard *$(SUFFIXES)) # コンパイルするソースの指定
TARGETS = $(SOURCES: .cpp=) # 全てのファイルでコンパイルを実行

2種類の変数

Makefileにも変数があります. 書き方は簡単で以下の通りです. var := hogeもしくはvar = hoge

上を見て「:==って何が違うんだ?」と思うのは自然でしょう. 前者は単純展開変数,後者は再帰展開変数に使います.

どういうことかといいますと,

:=の右辺は宣言時に評価されます. =の右辺はその変数が使われるたびごとに評価されます(宣言されたときには評価されません).

これで普通のプログラミング言語みたい代入をしているけど,右の式の評価に違いがあるんだなということはわかっていただけたと思います.

ユーザー定義関数(要はこれも変数)

次に$が気になったと思います.

これはユーザー定義関数といいます.実を言うと自分も使い方がよくわかっていないのですが,今回のコードでは以下のように使われています.

SOURCES = $(wildcard *$(SUFFIXES)) # コンパイルするソースの指定

ここでは$$(関数 関数を実行するファイル)と使われています.(wildardの説明は下でします.今のところはある関数に右のファイルが通されたという理解でお願いします) その後,=SOURCESに代入しています.

TARGETS = $(SOURCES: .cpp=) # 全てのファイルでコンパイルを実行

これは下で述べますが,SOURCESに対して.cppという処理を行っています 対象となる全てのSOURCESの拡張子を.cpp=の右辺に何も書かないことでバイナリファイルに変換しています.

ワイルドカード

上で後回しにしたwildcardの説明をします.

これはワイルドカード表記を使えるようにする関数です.

ワイルドカードとはWikipedia)によると

コンピュータなどの関連において、ワイルドカードは、検索などグロブの際に指定するパターンに使用する特殊文字の種類で、どんな対象文字、ないし文字列にもマッチするもののことである。カードゲームのワイルドカードに由来する呼称。

です.

つまり,文字列を検索する際に使う便利な表現方法です.

ワイルドカードでは*は「0文字以上のある文字列」という意味であり, (wildcard *$(SUFFIXES))SUFFIXES := .cppと合わせて (wildcar *.cpp)という考えることができます.

日本語にすると".cpp"で終わる文字列という意味です. 競プロはC++で書くので,全てのC++ファイルが対象となります.

正規表現

ワイルドカードと類似したものに,正規表現があります. コンパイラを書くのに使い,計算機科学には欠かせないものなので興味がある人はこっちも調べてみてください.

(サルるでもわかるから安心してください)

実行部分の解説

.PHONY:all # 仮想ファイルallを作る
all: $(TARGETS) # 仮想ファイルを作り,TARGETSを実行する
# $@: ターゲットファイル名
# $<: 最初に依存するファイル名
.cpp:
    $(CXX) $(CXXFLAGS) $@ $< # コンパイルオプションを使って,コンパイルを実行

次に実行している部分の説明です.

疑似ターゲット

Makefileを実行してディレクトリ上にファイルを作りたくないときに,.PHONYを使います.

本来Makefileでは実際に存在するファイルを前提に処理が行われますが,それが嫌なときに.PHONYを使うのです.

これを疑似ターゲットといいます.実際に存在するファイルに対して行う場合はターゲットといいます.

また,これを使うと実際に存在するファイルに邪魔されず処理ができます.

ここでは"all"という疑似ターゲットを作っています.

Makefileの基礎文法

次は簡単です.

Makefileの基礎文法は

作るファイル(ターゲット or 疑似ターゲット): 必要なファイル
    コマンドでの処理

となっています.

all: $(TARGETS) # 仮想ファイルを作り,TARGETSを実行する

ここではall(疑似ターゲット)を"TARGETS"から作っています.そして,"TARGETS"の処理は上で述べたように,全てのファイルで,.cppを実行することです.

.cpp:
    $(CXX) $(CXXFLAGS) $@ $< # コンパイルオプションを使って,コンパイルを実行

.cppは下で書かれているように-Wallコンパイルオプションとして,g++コンパイルされています(変数に代入されていることを想定して).

$@$<も変数です.左はターゲットファイル名を指定し,右は依存するファイル名をしていしています.

ここでは,全ての.cppファイルを対象としているので,例えばsample.cppというファイルがあれば,sampleというバイナリファイルにコンパイルされます.

処理の振り返り

一連の流れをまとめると

  1. 変数の宣言
  2. 疑似ターゲットを作って処理をする
  3. 処理ごとに変数が宣言される

という感じです.

実際の使い方

上と同じようにsample.cppを実行すると考えましょう.このときは

$ make
$ ./sample

とすると実行することができます.

よかったら自分だけのMakefileを使って簡単コンパイル生活を楽しんでください〜〜

ちなみに

このMakefileによる不利益が生じて一切の責任は取りません←言いたかった

最近バイトを始めた

最近バイトを始めた

授業・実験が忙しい3年生

授業と実験に忙殺され記事を全然書けていませんでしたどうも.

バイトを始めたのでそれに関連付けて無理やり記事にしました.

どんなバイト?

大学の研究室のバイトです.

計算機科学の応用に興味があり,関連した研究室を探していたところ,ちょうど見つかったので,応募したら運良く入ることができました

WEB系にしなかったのは?

前のインターン(昨年夏)で覚えたことは「知識がないのに行ってもろくなことにはならない」ということでWEB系の知識がない中で,よくわからない会社のよくわからない業務を任されることだけは回避したかったのです.

そこで,実力を考えWEB系はやめときました.

ただ,サマーインターンではWEB系に応募する予定なので勉強中デスネ^^;(進捗がない)

バイトのお勉強

4月に始めたのですが未だに業務っぽい業務がなく,6/22から留学するけど大丈夫か?となっているのですがとりあえずいつ始まってもいいように最近バイトに必要な生物の勉強をしています.

ただ,生物ってよくわからない分子や固有名詞がいっぺんに出てきて頭がパンクしそうになるので,まとめノートを作りながら生物学の一般的な教科書を読んでいます

カラー図解 アメリカ版 大学生物学の教科書 第1巻 細胞生物学 (ブルーバックス)

カラー図解 アメリカ版 大学生物学の教科書 第1巻 細胞生物学 (ブルーバックス)

1巻から読んでいますが,わかりやすいけど情報量が多いです(元々"LIFE"というアメリカの生物の教科書なのでアメリカンって感じです).

nya

今回は本当に内容がない...

次回に期待!

追記(5/15)

著作権的にまずそうなのでノートへのURLを消しました.ご了承ください

SICPを第4章まで読んでLisp(Scheme)のしょぼいインタプリタを作った

SICPを4章まで読んだ結果

コンピュータの仕組みの興味が湧いたので,実際にプログラミング言語を動かすことが大事だと思い何かしらの言語のコンパイラを作りたいと思いました.噂によるとSICPという本がLisp方言のSchemeコンパイラまで作るらしいので,春休みから取り掛かりました.

春休みを全て使うことはできなかったとはいえ実際に第4章まで終わった4/4(終わってないです) しかも「一応終わらせること」が目的で,「納得するように終わらせること」が目的ではなかったので,演習問題は割とネットの力を借りています.

コンパイラは無理でしたがこの段階で最低限の機能のついたインタプリタを作成することができました(本書の記述とネットの巨人の肩に乗っただけ?).

名付けてdioLispです.

インタプリタの機能の紹介

このLispインタプリタには最低限の機能しかないことを先に言っておきます.というのも色々な機能を盛り込むのもいいのですが,簡潔な言語としてSICPに採用されたSchemeの設計思想に反する気がして気が引けたからです(ただの手抜き).

  1. pair(cons,car,cdr)の実装
  2. 四則演算の実装
  3. coming soon...(実装サボってますすみません(T_T))

SICPを4章まで読んだ(インタプリタを作った)ことで得られたこと

インタプリタを作った過程で得られたことをざっと振り返ると以下のようになります.他にもある気がしますが,自分が目次を見て思い出すのはこれくらいです.

  • コンピュータ・サイエンスの基礎について入門できた(気がする)
  • 複雑な機構も単純な要素からなるとわかった
  • データの抽象化に関する処理に慣れた
  • 再帰関数に慣れた
  • 1つの事象を複数の手法で取り組むということが習慣になった
  • 手続きを再生産することの重要性を実感した
  • 破壊的代入の怖さがわかった
  • 並列(concurrent)処理と並行(parallel)処理の違いがわかった
  • ストリームという概念を把握した
  • 言語処理系の処理が説明できるようになった.

これから始めるつもりの人にアドバイス

各章に関して

個人的に難易度は

<易> 1章<<3章<<<2章<<<<4章 <難>

です.

私は1章から順番にやりました.本書ではそれまでの章の知識を前提知識として扱うので飛ばしてやることはおすすめしません.

演習問題について

演習問題を全て自分で解くのも大事ですが,すごく時間がかかると思うので時間と相談してやってください.ちなみに私は全て自分でやるのは贅沢でいいと思いますし,わからない部分は人のソースコードを見てしまうのも理解してしまえば実力はつくと思うのでいいと思います(ネットには全て自分で解く人もいますが,優秀なエンジニアさんばかりなので無理する必要はないと思うということです).

@beginners

あまり気負い過ぎないようにしてください.私は第4章は人の回答を見てばかりで自分の脳に欠陥があるんじゃないかと思い,春休みの終盤は本当に悲壮感でいっぱいでした...この本はかなり要求水準が高いと思うので,できなくても落ち込まないでください.

次の目標

Lispインタプリタを作った程度でコンピュータのことはまだまだわかりません(おい,そして君はまだ4章も終わってないじゃないか).

今後はもっと低レイヤーの部分がやりたいと思っています.今まで通りアルゴリズムとデータ構造の勉強をしながら,OS・CPUなどハードウェアの勉強も始めたいです(ちょうどハードウェアに関しては大学の授業も始まりました).

(CPUに関しては「CPUの創り方」という本を実は友人とやっているので多分次の記事はそれになります(?))

5章に関しては演習問題は適宜見ながら今後とりあえず読もうという感じです.

教科書

SICPのURLです

github.ioで自分のHPを作りました

github.ioで自分のHPを作りました.

題名の通りです.

前々からブログはこのはてなブログがあったのですが,自分のHPがなく企業へインターンの応募をする際やHP欄を埋めようとする際に面倒だったのでgithub.ioというgithubの提供するサービスを使って作ってみることにしました.

準備

github.ioについて調べる

公式サイトによれば

  1. 「"アカウント名"/github_io」というディレクトリをgithubに作ります.
  2. ディレクトリをクローンします.
  3. 後はディレクトリ内に色々ファイルを書けば完成です^^

ん???

ここで疑問が発生しました.

「どんなファイルを書けばいいんだろうか?」

調べたところhtmlとcssで書く方法とmarkdownで書く方法があるようでした.

このはてなブログmarkdownで書いているのですが,そればかりではつまらない,また今後困るだろうということで今回はhtmlとcssを勉強してついでにブログも書くことにしました.

※ちなみにmarkdownで楽に書きたい方はこちらの記事を読むことをおすすめします.

HTMLとCSSを勉強

こちらの

本当によくわかるらしい本をkindleに入れて読みながら進めてみました.

確かにネットで見ながらでもいいのですが,体系立った本で一回知識を入れると入れないとではその後関連した知識を吸収する速度が違うので読むだけ読んでみて作りました.

できたサイト

そしてできたサイトがこちらです.

それっぽいのができたのではないかと思っています.

日本語のサイトはブログでいいと思い,こちらは英語のサイトにしてみました.

英語もできるというアピールになっていいのではないでしょうか?(むしろ英語くらいしかできない...)(それも大してできない...)

AtCoderで緑色になるまでにしたこと

AtCoderで緑色になるまでにしたこと

どうもこんにちは.ABC120でようやく緑色になれました.

今回は自分が緑色になる軌跡などを話したいと思います.

f:id:sosodemonai:20190304171409p:plain
AtCoder Problemsの画面

自分がした緑色になるためには真似しない方が良いこと

緑色になるにあたり,あまりやらなくてもいいと思う例を上げたいと思います.

簡単な問題を解きまくる

自分はコンプリート癖があるのでとりあえず解ける問題を解きまくりました.

ABCのA・B問題やAGC, ARCのA問題などをいわゆる虚無埋めしまくりました.

小学生の頃の算数のドリルの問題をひたすら解くようなもので,時間効率は良くないので真似をしないほうがいいです(タイピングは多少早くなります).

難しい問題をパスする

私は少しでも「難しい!」と思った問題はまだ自分のレベルじゃないとパスしました.

しかし,何事もそうなのですが「自分のレベルよりもちょっと高い」問題を「頭を使って」こなすのが一番実力を上げるのに有効だと思います(競プロではいわゆる考察力を付けるために?).

私は知識のない状態でのこういう考察力を付ける修行みたいな期間があまり好きでなく,ある程度典型的なアルゴリズムを使えるようになってから頭を使おうと思っていたので(究極的にはすべての問題を解くなら残った過去問にはそういう「頭を使う」問題しか残らなくなるはずですし)スルーしました.

標準入出力がわからない状態でとりあえず出る

初期はパフォーマンスはマイナスがデフォルトでした...

というのも「とりあえず出よう!」と思って標準入出力がわからない(しかもプログラミングも始めたばかりの)状態で出たからです.

直近5回のパフォだと,緑,緑,緑,緑,水ですが,最初の5回は灰,灰,灰,灰,茶です.

f:id:sosodemonai:20190304171404p:plain
パフォーマンスがひどい

パフォーマンスが上がっても中々緑色にならなかったのは結構精神的に辛かったので,最低A問題が解けるくらいになるまではコンテストに出ない方がいいんじゃないかなぁと思います.

逆にやってよかったこと.

アルゴリズムとデータ構造の勉強をする

AOJ本でアルゴリズムとデータ構造に関する勉強をしたのが良かったです.

これでTwitterなどでコンテスト後に他の人が呟いている内容が少しは理解できるようになりました(実装は(^q^)...).

緑色になるメリット

私はあまり賢くないので過去問過学習で乗り切りましたが,副次的にコードを書く習慣がつきコーディング力は前よりもかなり上がりました.

あと,情報系の学科に所属しているのですが緑色でなかったことに結構コンプレックスがありましたが,これが若干解消されました().

努力でなんとかなるので多少自分に自信が持てるという意味でも緑色になれてよかったです.

水色になるために

蟻本をやるつもりです.

AtCoder版!蟻本というコンテンツが無料で公開されているので,ここにある問題を解いて早めに水色になりたいです.)