Skip to content

Instantly share code, notes, and snippets.

@uta8a
Last active March 3, 2019 04:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uta8a/e972c65a1c4910877dd0e455d1f0ccbc to your computer and use it in GitHub Desktop.
Save uta8a/e972c65a1c4910877dd0e455d1f0ccbc to your computer and use it in GitHub Desktop.
競プロでmake使ってみた

Makeとは

目的: C++を使う競プロで競技中になるべくコマンドラインを触らないようにして楽をするためのMake入門

Make入門

makeとは

  • makeはコンパイル自動化ツールである。(依存関係を含む複雑なコンパイルや、別々の環境用にコンパイル方法を指定したいときに使う)
  • makeはUNIX標準ツールとして用意されている。今回はGNU Makeを扱う。
  • 困ったときは、 https://www.gnu.org/software/make/manual/ を見ればOK。

挙動
make : Makefileというファイル内のallというコマンドが実行される。
make -f sample.mk sample1 : Makefileを指定して、その中のsample1というコマンドを実行

おそらく、競プロで使うならMakefileをフルパス指定しておいて、それをproconとかでaliasしておく感じになりそう

  • makeを二回実行→up to dateと表示されるので、おそらく前回のコンパイル元のソースコードを記憶している…?→タイムスタンプを比較しているらしい。それによって、変更のあるものだけ再コンパイルするようになっている。

文法

targets: prerequisites
  recipe
  ...

上のように、ターゲット(生成されるもの)と依存関係にあるものとそれらに対する操作という3つで構成されている。recipeの前にはtabを入れる。
変数名の慣習
暗黙の規則で、C, C++に対しては以下のように変数を設定する。

  • CC : Cコンパイラ
  • CFLAGS : Cコンパイラのフラグ
  • CXX : C++コンパイラ
  • CXXFLAGS : C++コンパイラのフラグ

暗黙の規則と変数は make -p オプションで表示できる

test.mk

# variable
CC = gcc
OPTIMIZE = -O2
CFLAGS = $(OPTIMIZE) -Wall
# command
all: test
test: test.c
  $(CC) $(CFLAGS) -o $@ $<

例の解説

  • make -f test.mk で実行されるのは gcc -O2 -Wall -o test test.c になる。
  • まず、上のコマンドではデフォルトでallが呼ばれる。
  • allはtestを呼ぶ

testを見ていく

  • test: test.cより、targetはtest、依存関係にあるのはtest.c
  • $(CC) $(CFLAGS) は変数を展開しているだけなのでそのまま gcc -O2 -Wall
  • $@ はtargetのfilenameを指す。ここではtest
  • $< はprerequisitesの一つ目を指す。ここではtest.c

記号については こちら を参照

競プロでMakeを使ってみる

環境

  • WSL ubuntu18.04

要件定義

AtCoderでは、以下のように実行される(C++14 (GCC 5.4.1))

g++ -std=gnu++1y -O2 -I/opt/boost/gcc/include -L/opt/boost/gcc/lib -o a.out Main.cpp

とりあえずこれに準拠する

g++ -std=gnu++1y -O2 -Wall -o a a.cpp

最終的には、こんな感じにしたい
デバッグ用に分ける?

g++ -std=gnu++1y -Wall -g -fsanitize=undefined -D_GLIBCXX_DEBUG a.cpp
  • -Wall は警告を多めに出す
  • -g はデバッグ情報追加
  • -fsanitize=undefined は未定義動作の検出
  • -D_GLIBCXX_DEBUG はデバッグモード

このへんはfasnitizeならこのへんを見る。
あと本筋ではないが慣れてきたらvalgrind使いたい
以上により、Makefileは以下のようにしてproconのルートに置くことにした
procon.mk

# variable
CXX = g++
CXXFLAGS = -std=gnu++1y -Wall
CXXFLAGS_RELEASE = -O2
CXXFLAGS_DEBUG = -g -fsanitize=undefined -D_GLIBCXX_DEBUG
targets = $(patsubst %.cpp, %, $(filter %.cpp, $(shell ls -al)))

# command
$(targets): %: %.cpp
        $(CXX) $(CXXFLAGS) $(CXXFLAGS_RELEASE) -o $@ $<
all:
        $(targets)
debug: $(targets).cpp
        $(CXX) $(CXXFLAGS) $(CXXFLAGS_DEBUG) $<

~/.bash_aliases

alias chan='make -f ~/procon/procon.mk'

使い方

  • ディレクトリ構造は以下の通り
/procon
|-procon.mk
|-/atcoder
  |-/abc119
    |-/a
      |-a.cpp
      |-a
      |-/test
        |-/sample-1.in
    |-/b
    |-/c
    |-/d
  • 以下のように使う
cd ~/procon/contests/atcoder/abc119/a
chan # 実行ファイル作成
./a < input.txt # 個人的に作ったケースを試したい場合
oj test -c ./a # kimiyukiさんのoj
chan debug # debug mode
  • 別の問題に移るときディレクトリ移動がめんどくさい(nextとかでa→bに移る?どうせ何かしら文字を打つ必要があるならそこは仕方ないような気もする)
  • このディレクトリ移動については、GUIでなんとかできそう
  • cleanコマンドの実行(各ディレクトリごとはめんどうなので、chan delete-all とかでmv -iv噛ませてprocon配下の実行ファイルすべて消し去るようにしたい。ここは気を遣う。)

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment