明日にはでっかい太陽が昇るかもしれません。

「覚悟」とは!! 暗闇の荒野に!!進むべき道を切り開く事だッ!

競技プログラミングはじめました

年末だけど、なにかあたらしいことを始めたいなぁとおもったので、以前から興味があった競技プログラムを始めてみました。

AtCoder (アットコーダー)

多くの競技プログラムサイトは英語圏のものなのですが、上記のAtCoderは完全日本語なので、「問題文が読めない!」という問題はないので安心して始められます(笑)

TopCoderなどの英語圏にもチャレンジしたいけど、まずは競技プログラムに慣れるところからということで。

競技プログラムはアルゴリズム要素が多くなるのだけれど、いままで勉強してこなかったので初歩の初歩から楽しんで取り組める感じ。

ケアレスミスもあったりして、改めて自分のプログラマーとしての実力もまだまだだということを実感しました。

他の人の回答も見られるので、学習効果は高いと思います。

仕事のプログラムは他人の解法と比べることはできませんからね。

Qemu を使いこなすために

組み込みを仕事にしているため、よく機材不足や新規基盤の開発遅れなどのトラブルが起きます。

そこで、Qemu を活用できればと思っていたところに良い記事が見つかったので写経してみました。

qiita.com

ところが、ドライバの作成でコンパイルエラーが発生!!

ハードとして x86_64 環境、カーネルは 4.2 を選んだけど、組み合わせの問題はありがちなので解決していく。

> make
make -C path/to/linux-4.2/ M=/path/to/custom_d
evices/test_pci modules
make[1]: Entering directory `/path/to/linux-
4.2'
  CC [M]  /path/to/custom_devices/test_pci/test_pci_driver.o
In file included from ./arch/x86/include/asm/bitops.h:16:0,
                 from include/linux/bitops.h:36,
                 from include/linux/kernel.h:10,
                 from include/linux/list.h:8,
                 from include/linux/module.h:9,
                 from /path/to/custom_devices/test_pci/test_pci_driver.c:7:
./arch/x86/include/asm/arch_hweight.h: In function ‘__arch_hweight64’:
./arch/x86/include/asm/arch_hweight.h:53:42: error: expected ‘:’ or ‘)’ before ‘POPCNT64’
  asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT)
                                          ^
MENT’
  b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t"
                            ^
./arch/x86/include/asm/arch_hweight.h:53:7: note: in expansion of macro ‘ALTERNATIVE’
  asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT)
       ^
In file included from ./arch/x86/include/asm/pgtable_types.h:250:0,
                 from ./arch/x86/include/asm/processor.h:18,
                 from ./arch/x86/include/asm/thread_info.h:49,
                 from include/linux/thread_info.h:54,
                 from ./arch/x86/include/asm/preempt.h:6,
                 from include/linux/preempt.h:64,
                 from include/linux/spinlock.h:50,
                 from include/linux/seqlock.h:35,
                 from include/linux/time.h:5,
                 from include/linux/stat.h:18,
                 from include/linux/module.h:10,
                 from /path/to/custom_devices/test_pci/test_pci_dri
ver.c:7:
... 省略 ...

どうやら、標準ヘッダの 64bit 依存部分に問題があるらしい。

と思ったら、 ARCHCROSS_COMPILE を指定し忘れているだけだった。

obj-m += test_pci_driver.o

export ARCH = arm
export CROSS_COMPILE = /path/to/buildroot/output/host/usr/bin/arm-buildroot-linux-uclibcgnueabi-

KERNELDIR = /path/to/buildroot/output/build/linux-4.2/

all:
        make -C $(KERNELDIR) M=$(PWD) modules

clean:
        make -C $(KERNELDIR) M=$(PWD) clean

すぐに気づいたけど、ダサすぎる。

ドライバ作成とか慣れていないのがバレバレである。

ビルドができたところで、問題が発生した。

ビルド環境は docker のコンテナ内に作成しているのだが、コンテナにはループバックデバイスがないため、 Qemu のルートファイルシステムがマウントできないのである!

> sudo mount -t ext2 -o loop,rw ../../buildroot/output/images/rootfs.ext2 /mnt/
mount: Could not find any loop device. Maybe this kernel does not know
       about the loop device? (If so, recompile or `modprobe loop'.)

いろいろ調べたけど、今のコンテナの状態ではできないっぽい。( rootfs をホストから隔離しなければできたり、 loop デバイスをコンテナにも見せたりできるらしいけど、本筋からずれるから今はやらない。でも、開発環境として本格的に利用するのであれば後者を試してみないと)

rootfs は buildroot で作成しているので(カーネルもだけど)、直接組み込むことで解決した。

$ qemu-system-arm -m versatilepb -kernel output/images/zImage -drive file=output/images/rootfs.ext2,if=scsi -append "root=/dev/sda console=ttyAMA0,115200" -nograpic -device test_pci

insmod してみたけど、 Oops になってしまった。。。

今後は、問題を解決してアプリを作成→業務で使っているデバイスに近づくように拡張。と進めていこう。

# insmod test_pci_driver.ko
test_pci 0000:00:0d.0: enabling device (0100 -> 0103)
*** /home/embryo/workspa(321) test_pci_probe: PCI enabled for test_pci
*** /home/embryo/workspa(327) test_pci_probe: mmio_base: 50002000, mmio_length: 50002000, m
mio_flags: 1000
*** /home/embryo/workspa(346) test_pci_probe: pio_base: 1400, pio_length: 100, pio_flags: 4
0101
------------[ cut here ]------------
kernel BUG at arch/arm/mach-versatile/pci.c:87!
Internal error: Oops - BUG: 0 [#1] ARM
Modules linked in: test_pci_driver(O+)
CPU: 0 PID: 71 Comm: insmod Tainted: G           O    4.2.0 #1
Hardware name: ARM-Versatile PB
task: c79d6380 ti: c79e8000 task.ti: c79e8000
PC is at __pci_addr.isra.1+0x24/0x2c
LR is at versatile_read_config+0x1c/0xb8
pc : [<c00148d8>]    lr : [<c001498c>]    psr: 20000093
sp : c79e9d20  ip : c0014970  fp : 38623d9c
r10: 00000001  r9 : bf001798  r8 : 00000000
r7 : bf001960  r6 : 0000fefe  r5 : 00000002  r4 : 00000068
r3 : 00000002  r2 : 0000fefc  r1 : 00000068  r0 : 00000000
Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 00093177  Table: 07b14000  DAC: 00000015
Process insmod (pid: 71, stack limit = 0xc79e8190)
Stack: (0xc79e9d20 to 0xc79ea000)
9d20: c79e9d64 60000013 bf0012f0 c017efb0 c79e9d3c c79e9d44 c7870800 00000000
9d40: bf0012f0 c7870800 bf001960 bf000c08 00001400 00000100 00040101 20000013
9d60: bf001750 00000000 c7870800 c7870868 bf001750 00000000 c7870800 bf00171c
9d80: bf001798 c01883a4 c0188330 c7870868 c042bfe0 bf001750 c03f0b40 00000003
9da0: c79dc280 c01cbd48 c7870868 bf001750 c787089c c03f0b40 00000000 c01cbf70
9dc0: 00000000 bf001750 c01cbee4 c01ca470 c7823d0c c7861d50 bf001750 c7b181e0
9de0: 00000000 c01cb5b4 bf0012f0 c79dc288 bf001750 bf001750 c03ddf20 c79d8760
9e00: bf003000 c01cc730 bf001790 c03ddf20 c03ddf20 c0009604 c03f0920 c0036a38
9e20: 00000000 00000000 00000000 c0025f98 000080d0 00000000 c79e9e38 c79e9e38
9e40: bf001828 c7b08000 c03dde00 c7fec9c0 c7ef9000 00000000 00000000 00000000
9e60: c79dc280 00000001 bf0017e0 c79dc288 c79d8720 bf0017e0 bf001828 00000001
9e80: 38623d9c c02cf920 c79e9f48 c79dc288 c79e9f48 c79dc288 00000001 c0056768
9ea0: bf0017ec 00007fff 00000000 c0054238 00000000 00000000 00000000 00000124
9ec0: c898b170 bf00193c bf0017ec 00000000 00000000 c0085004 00000004 c0085cd8
9ee0: ff000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9f00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9f20: c0056bc8 00003545 00000000 000bb55d c898c545 000b8008 c79e8000 00000000
9f40: 00000000 c0056c38 c8989000 00003545 c898ac98 c898ab49 c898c018 00001970
9f60: 00001b60 00000000 00000000 00000000 0000001f 00000020 00000017 00000000
9f80: 00000011 00000000 00000000 beb60f45 000b8008 000b8018 00000080 c000a444
9fa0: c79e8000 c000a2c0 beb60f45 000b8008 000b8018 00003545 000b8008 00000000
9fc0: beb60f45 000b8008 000b8018 00000080 000b669c 00000000 b6fa0f70 00000000
9fe0: b6f4c3c8 beb60c94 0001c994 b6f4c3d8 a0000010 000b8018 00000000 00000000
[<c00148d8>] (__pci_addr.isra.1) from [<c001498c>] (versatile_read_config+0x1c/0xb8)
[<c001498c>] (versatile_read_config) from [<c017efb0>] (pci_bus_read_config_word+0x4c/0x60)
[<c017efb0>] (pci_bus_read_config_word) from [<bf000c08>] (test_pci_probe+0x1d8/0x558 [test
_pci_driver])
[<bf000c08>] (test_pci_probe [test_pci_driver]) from [<c01883a4>] (pci_device_probe+0x74/0x
c8)
[<c01883a4>] (pci_device_probe) from [<c01cbd48>] (driver_probe_device+0x124/0x2c0)
[<c01cbd48>] (driver_probe_device) from [<c01cbf70>] (__driver_attach+0x8c/0x90)
[<c01cbf70>] (__driver_attach) from [<c01ca470>] (bus_for_each_dev+0x70/0xa0)
[<c01ca470>] (bus_for_each_dev) from [<c01cb5b4>] (bus_add_driver+0x188/0x210)
[<c01cb5b4>] (bus_add_driver) from [<c01cc730>] (driver_register+0x78/0xf8)
[<c01cc730>] (driver_register) from [<c0009604>] (do_one_initcall+0x80/0x1e0)
[<c0009604>] (do_one_initcall) from [<c02cf920>] (do_init_module+0x58/0x1b4)
[<c02cf920>] (do_init_module) from [<c0056768>] (load_module+0x18f0/0x1cf4)
[<c0056768>] (load_module) from [<c0056c38>] (SyS_init_module+0xcc/0x124)
[<c0056c38>] (SyS_init_module) from [<c000a2c0>] (ret_fast_syscall+0x0/0x38)
Code: e1801401 e1810002 e28004e9 e12fff1e (e7f001f2)
---[ end trace d58ace19ffed3147 ]---
Segmentation fault
# main-loop: WARNING: I/O thread spun for 1000 iterations

、、、

ケアレスミスがいくつか合ったけど、無事ロードができた。

# insmod test_pci_driver.ko
test_pci 0000:00:0d.0: enabling device (0100 -> 0103)
*** /home/embryo/workspa(321) test_pci_probe: PCI enabled for test_pci
*** /home/embryo/workspa(327) test_pci_probe: mmio_base: 50002000, mmio_length: 1000, mmio_flags: 40200
*** /home/embryo/workspa(346) test_pci_probe: pio_base: 1400, pio_length: 100, pio_flags: 40101
*** /home/embryo/workspa(361) test_pci_probe: PCI Vendor ID: fefe, Device ID: 1
*** /home/embryo/workspa(366) test_pci_probe: success allocate I/O region
*** /home/embryo/workspa(369) test_pci_probe: device irq: 94
*** /home/embryo/workspa(400) test_pci_probe: test_pci driver(major 253) installed.

*** /home/embryo/workspa(420) test_pci_probe: cdma_addr: 7886000

後は、アプリを作ってアクセスしてみよう!

ビルド環境の構築を行う

どんなツールを使うのか

メインで利用するのは C 言語になるので、C 言語界隈の気になるツールを片っ端から導入し試してみる。

私は組み込み開発従事者なので、どうしてもGUIIDEなどの派手なツールの利用は機会がありません。(大抵のプロジェクトで利用できるCUI最高!という感じ)

ツール 目的 備考
Vim エディタ 経験値はひよこレベル
ag 検索 高速 grep 。ファイル名も grep の 50% !!
cmake ビルドスクリプト gnu make の Makefile ジェネレータ?
GCC コンパイラ 言わずと知れた業界標準コンパイラ
LLVM+Clang コンパイラ 次世代のコンパイラ。これからの時代は複数コンパイラに対応しないとね
ClangFormat フォーマッタ Clangに含まれるツール。コードレビューでスタイルを指摘するのはうんざり
cpplint フォーマットチェッカ Phython の単一コードなのでカスタマイズすれば利用の幅が広がるかも
CppUTest ユニットテスト 組み込みも意識した GoogleTest と双璧をなすツール
CppCheck 静的アナライザ フリーツールの中では標準か!?
Valgrind 動的アナライザ 使ったこと無いけど、歴史は長い。
Git バージョン管理 業界の新標準。
bugspots バグ予測 Google 謹製。 Git のコミット履歴から予測する

Vim をインストールする

Vim 自体はすでにインストール済みなのですが、標準では Lua を利用できないため NoeBundle の力をフル活用できません。

そのため、 Lua を利用できるようにするため、 vim-nox パッケージをインストールします。

$ sudo apt-get install -y vim-nox
  • vim-nox インストール前
$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Jan  2 2014 19:39:32)
...
+dialog_con      -lua             +rightleft       +windows
...
  • vim-nox インストール後
$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Jan  2 2014 19:39:34)
...
+dialog_con      +lua             +rightleft       +windows
...

次に、 Vim を便利に使うための NeoBundle 周りの環境を構築する。

もう、数回目の構築になるが、毎回ベストプラクティスを探して数時間かかってしまう。。。

何はともあれ、 ~/.vimrc に NeoBundle の設定(インストールするプラグイン)を記載していく。

$ cat ~/.vimrc
" neobundle settings {{{
if has('vim_starting')
  set nocompatible

  if !isdirectory(expand('~/.vim/bundle/neobundle.vim/'))
    echo 'install neobundle...'
    :call system('git clone git://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim')
  endif

  set runtimepath+=~/.vim/bundle/neobundle.vim
endif

call neobundle#begin(expand('~/.vim/bundle'))
let g:neobundle_default_git_protocol='https'

NeoBundleFetch 'Shougo/neobundle.vim'
NeoBundle 'Shougo/unite.vim'
NeoBundle 'Shougo/neomru.vim', {
  \ 'depends' : 'Shougo/unite.vim'
  \ }
NeoBundle 'Shougo/unite-outline', {
  \ 'depends' : 'Shougo/unite.vim'
  \ }
NeoBundle 'Shougo/vimproc', {
  \ 'build' : {
  \   'windows' : 'make -f make_mingw32.mak',
  \   'cygwin'  : 'make -f make_cygwin.mak',
  \   'mac'     : 'make -f make_mac.mak',
  \   'unix'    : 'make -f make_unix.mak'
  \   }
  \ }
if has('lua')
  NeoBundleLazy 'Shougo/neocomplete.vim', {
  \ 'depends'  : 'Shougo/vimproc',
  \ 'autoload' : { 'insert' : 1, }
  \ }
endif
NeoBundleLazy 'Shougo/vimshell', {
  \ 'depends'  : 'Shougo/vimproc',
  \ 'autoload' : {
  \   'commands' : [{ 'name' : 'VimShell', 'complete' : 'customlist,vimshell#complete' },
  \                 'VimShellExecute', 'VimShellInteractive',
  \                 'VimShellTerminal', 'VimShellPop'],
  \   'mappings' : ['<Plug>(vimshell_switch)']
  \   }
  \ }
NeoBundle 'Townk/vim-autoclose'
NeoBundleLazy 'tpope/vim-endwise', {
  \ 'autoload' : { 'insert' : 1 }
  \ }
NeoBundleLazy 'Shougo/neosnippet', {
  \ 'depends'  : 'Shougo/neosnippet-snippets',
  \ 'autoload' : {
  \   'insert'    : 1,
  \   'filetypes' : 'snippet'
  \   }
  \ }
NeoBundle 'Shougo/neosnippet-snippets'
NeoBundle 'itchyny/lightline.vim'
NeoBundle 'nathanaelkane/vim-indent-guides.git'

NeoBundle 'tomasr/molokai'

" install check for plugin
NeoBundleCheck
call neobundle#end()
" }}}

" neocomplete settings {{{
let g:neocomplete#enable_at_startup               = 1
let g:neocomplete#auto_completion_start_length    = 3
let g:neocomplete#enable_ignore_case              = 1
let g:neocomplete#enable_smart_case               = 1
let g:neocomplete#enable_camel_case               = 1
let g:neocomplete#use_vimproc                     = 1
let g:neocomplete#sources#buffer#cache_limit_size = 1000000
let g:neocomplete#sources#tags#cache_limit_size   = 30000000
let g:neocomplete#enable_fuzzy_completion         = 1
let g:neocomplete#lock_buffer_name_pattern        = '\*ku\*'
" }}}

" vimshell settings {{{
nmap <silent> vs :<C-u>VimShell<CR>
nmap <silent> vp :<C-u>VimShellPop<CR>
" }}}

" neosnippet settings {{{
imap <C-k> <Plug>(neosnippet_expand_or_jump)
smap <C-k> <Plug>(neosnippet_expand_or_jump)
" }}}

" common settings {{{
filetype plugin indent on

colorscheme molokai
set t_Co=256
set background=dark
syntax on

set list
set listchars=tab:>.,trail:_,extends:>,precedes:<,nbsp:%,eol:$
function! ZenkakuSpace()
  highlight ZenkakuSpace cterm=reverse ctermfg=DarkMagenta gui=reverse guifg=DarkGray
endfunction
if has('syntax')
  augroup ZenkakuSpace
    autocmd!
    autocmd ColorScheme * call ZenkakuSpace()
    autocmd BufNew,BufRead * match ZenkakuSpace /!!/
  augroup END
  call ZenkakuSpace()
endif

set number
set ts=4
set sw=4
set showmatch
set ruler
set scrolloff=7
set laststatus=2
set showmode
set showcmd

set encoding=utf-8
set fileencodings=iso-2022-jp,euc-jp,euc-jisx0213,sjis,utf-8
set fileformats=unix,dos,mac
set formatoptions+=mm
if exists('&ambiwidth')
  set ambiwidth=double
endif

set pastetoggle=

set wrapscan
set ignorecase
set smartcase
set incsearch
set hlsearch

set nobackup
set noswapfile
" }}}

いつもながら結論が出ないな。ファイラも入れたいが、 vimfilerNERDTree もどこか合わなかったので、今回は見合わせた。

ag のインストール

最新を使いたいので、ソースからインストールする。

手順は 公式 の通りに。

ビルドに必要なツールのインストール

$ sudo apt-get install -y automake pkg-config libpcre3-dev zlib1g-dev liblzma-dev

ビルド

$ tar zxvf 0.31.0.tar.gz
$ cd the_silver_searcher-0.31.0/
$ ./build.sh
$ sudo make install
$ ag --version
ag version 0.31.0

Features:
  +jit +lzma +zlib

cmake のインストール

公式で配布されるインストールスクリプトは、対話的になっているため、圧縮ファイルからインストールする。

### ファイルのダウンロード&展開
$ curl -LO https://cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz
$ tar zxvf cmake-3.3.2-Linux-x86_64.tar.gz
$ sudo cp -af cmake-3.3.2-Linux-x86_64 /opt/toolchain/cmake
$ sudo chown root:root -R /opt/toolchain/cmake/
### 環境変数へパスを通す
$ echo 'PATH="/opt/toolchain/cmake/bin:$PATH"' >> ~/.profile
$ . ~/.profile
### 実行確認
$ cmake --version
cmake version 3.3.2

CMake suite maintained and supported by Kitware (kitware.com/cmake).

GCC のインストール

インストール済みのため省略!

LLVM+Clang のインストール

以前の記事を参考にインストールします。

agekuno.hatenablog.com

$ sudo apt-get install -y libpython2.7 libpython2.7-dev swig libedit2 libedit-dev libncurses5-dev libxml2-dev
$ git clone http://llvm.org/git/llvm.git
$ cd llvm
$ (cd tools && git clone http://llvm.org/git/clang.git)
$ (cd projects && git clone http://llvm.org/git/libcxx)
$ (cd projects && git clone http://llvm.org/git/libcxxabi)
$ (cd projects && git clone http://llvm.org/git/compiler-rt)
$ (cd tools && git clone http://llvm.org/git/lldb)
$ (cd tools && git clone http://llvm.org/git/lld)
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/toolchain/llvm+clang -DCMAKE_C_COMPILER=/usr/
bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ ..
$ make -j 2
$ sudo make install
$ echo 'PATH="/opt/toolchain/llvm+clang/bin:$PATH"' >> ~/.profile
$ . ~/.profile

cpplint のインストール

Github からクローンします。

github.com

$ git clone https://github.com/google/styleguide.git
$ sudo mv styleguide /opt/analyzer/
$ sudo chown root:root -R /opt/analyzer/styleguide

これから使うので、最終的なビルドシステムからは外すかも。

CppUTest のインストール

こちらも、 Github からクローンしインストールします。

$ git clone https://github.com/cpputest/cpputest.git
$ cd cpputest
$ mkdir cpputest
$ cd cpputest
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/toolchain/cpputest -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCOVERAGE=ON ..
$ make
$ sudo make install

CppCheck のインストール

こちらも、 Github からクローンし、インストールします。

github.com

有料の静的解析ツール(e.g. coverity)については、プロジェクトにより利用できるかどうかが変わるため、基本的な品質をキープするために確実に導入できるツールが必要になると考えています。

$ git clone https://github.com/danmar/cppcheck.git
$ cd cppcheck
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/analyzer/cppcheck -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release ..
$ make
$ sudo make install
$ sudo bash -c 'echo "/opt/analyzer/cppcheck/lib" > /etc/ld.so.conf.d/cppcheck.conf'
$ echo 'PATH="/opt/analyzer/cppcheck/bin:$PATH"' >> ~/.profile
$ . ~/.profile

Valgrind のインストール

ソースからインストールします。

$ curl -LO http://valgrind.org/downloads/valgrind-3.11.0.tar.bz2
$ tar jxvf valgrind-3.11.0.tar.bz2
$ cd valgrind-3.11.0
$ ./configure --prefix=/opt/analyzer/valgrind
$ make
$ sudo make install
$ echo 'PATH="/opt/analyzer/valgrind/bin:$PATH"' >> ~/.profile

Valgrind も、使ったこと無いので、どんな感じになるのかは試してからのお楽しみ。

Git のインストール

すでに導入済みなので省略。

bugspots のインストール

bugspots は ruby せいなので、 gem でインストールできます。

github.com

$ gem install bugspots

bugspots はコミットログを解析するため、コミットログに工夫をする必要があります。(デフォルトでは、 fix が含まれるコミットログを不具合修正コミットとみなす)

この辺りは、ルール付けをして新しいコミットから適用すれば、すんなり運用に乗せられそう。

あとは、 cmake の代わりに gyp とかも気になるけど、情報量が少ないのでひとまず cmake を使い込んでみる。

cmake に不満がでたら gyp も検討してみよう。

ドキュメント系ツールを一斉に導入してみる

気になるところ

ドキュメント系ツールについては、どの程度業務でも活用できそうなのか記になるので、早速環境を作成してみる。

pandoc のインストール

pandocHaskell という(私には)あまり馴染みが無い言語で作成されているので、まずは Haskell の実行環境からインストールする。

$ sudo apt-get install -y haskell-platform

直接、 apt から pandoc をインストールすることもできるが、バージョンが古いっぽいので、地道にインストールしていく。

そうすると、 apt と似たような、 Haskell のパッケージマネージャである cabal が利用できるようになるので、 pandoc をインストールする。

まずは、 cabal 自身をアップデートする

$ cabal update
$ cabal install Cabal cabal-install

古い(1.18以前の) cabal ではこの後使う sandbox コマンドが利用できないので、今更新した cabal にパスを通し直す。

export PATH=~/.cabal/bin:$PATH

~/.profile などに同じパスを記載しておくこと。

サンドボックスを作成する

$ mkdir ~/pandoc
$ cd ~/pandoc
$ cabal sandbox init

ビルドする

$ cabal install pandoc

かなりの時間がかかるので、コーヒーブレイクでも入れましょう。

ビルドが終わったら、オブジェクトを ~/.cabal/bin などにコピーし、シェルから参照できるようにします。

asciidoctor のインストール

本家 AsciiDoc は Python 製なのですが、普及度などを調べると GitHub でも採用されている(らしい) Ruby 製の AsciiDoctor のほうが良さそう(バージョンアップも活発)なので、そちらをインストールしてみる。

ruby のインストール

手順は Setup Ruby On Rails on Ubuntu 14.04 Trusty Tahr を参考にしてみた。

まずは、 ruby のビルドに必要なライブラリのインストールを行う。( Python に比べてインストールのハードル高すぎ。。。)

$ sudo apt-get update
$ sudo apt-get install zlib1g-dev libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev libffi-dev

rbenv ( Python の virtualenv のようなもの?)をインストールして、 rbenv 環境に ruby をインストールする。

$ cd
$ git clone git://github.com/sstephenson/rbenv.git .rbenv
$ echo 'PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.profile
$ echo 'eval "$(rbenv init -)"' >> ~/.profile
$ 
$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ echo 'PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.profile
$ 
$ git clone https://github.com/sstephenson/rbenv-gem-rehash.git ~/.rbenv/plugins/rbenv-gem-rehash
$ 
$ . ~/.profile
$ 
$ rbenv install 2.2.3
$ rbenv global 2.2.3
$ ruby -v

これで、以下の様な表示が出れば、 ruby のインストールは完了となる。

ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]

AsciiDoctor のインストール

公式の手順 によれば、

$ gem install asciidoctor

とすれば良いのだけれど、SSL 関係でエラーが発生します。

$ gem install asciidoctor
ERROR:  Could not find a valid gem 'asciidoctor' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)

そこで、一時的に HTTP で更新できるようにします。

$ ~$ gem source --add http://rubygems.org
https://rubygems.org is recommended for security over http://rubygems.org

Do you want to add this insecure source? [yn]  y
http://rubygems.org added to sources

再び、 AsciiDoctor のインストールにトライします。

$ gem install asciidoctor
Fetching: asciidoctor-1.5.2.gem (100%)
Successfully installed asciidoctor-1.5.2
Parsing documentation for asciidoctor-1.5.2
Installing ri documentation for asciidoctor-1.5.2
Done installing documentation for asciidoctor after 4 seconds
WARNING:  Unable to pull data from 'https://rubygems.org/': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)
1 gem installed
$ asciidoctor --version
Asciidoctor 1.5.2 [http://asciidoctor.org]
Runtime Environment (ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]) (lc:US-ASCII fs:US-ASCII in:- ex:US-ASCII)

今度は、(SSL の警告がでつつも)インストールできました。

最後に、HTTP による更新を無効にします。

$ gem source --remove http://rubygems.org
http://rubygems.org removed from sources

でも、根本的なエラーの原因は取り除けていないため、都度 HTTP での更新をできるようにしないとダメなのがダサいな。。。

オプションのインストール

後は、それっぽいオプションをインストールします。

$ gem install --no-ri --no-rdoc asciidoctor-diagram
$ gem install --no-ri --no-rdoc coderay pygments.rb thread_safe

graphviz のインストール

手抜きのため、 apt でインストールします。

$ sudo apt-get install -y graphviz

最新版( 2.38 )じゃないけど気にしない。

$ dot -V
dot - graphviz version 2.36.0 (20140111.2315)

texlive のインストール

GitHubUbuntu 用のインストールスクリプト公開 されているので、ありがたく利用する。

github.com

$ sudo bash -c "curl -L https://github.com/scottkosty/install-tl-ubuntu | bash"
$ echo 'PATH="/usr/local/texlive/2015/bin/x86_64-linux:$PATH"' >> ~/.profile
$ . ~/.profile

かなり時間がかかるので、散歩にでも出かけましょう。

完了すれば、 TeX 関連コマンドが利用可能になります。

$ tex --version
TeX 3.14159265 (TeX Live 2015)
kpathsea version 6.2.1
Copyright 2015 D.E. Knuth.
There is NO warranty.  Redistribution of this software is
covered by the terms of both the TeX copyright and
the Lesser GNU General Public License.
For more information about these matters, see the file
named COPYING and the TeX source.
Primary author of TeX: D.E. Knuth.

最後に、公式サイトの TeX Live パッケージをインストールした場合、 aptTeX Live に依存したパッケージをインストールしてしまうと、ついでに apt でも TeX Live (古いバージョン)がインストールされてしまうらしいので、ダミーパッケージを apt でインストールして、依存関係で問題が出ないようにします。

Integrating vanilla TeX Live with Debian

$ sudo mkdir /tmp/tl-equivs
$ cd /tmp/tl-equivs/
$ sudo equivs-control texlive-local
$ sudo vim texlive-local
### 編集内容は後述
$ sudo equivs-build texlive-local
$ sudo dpkg -i texlive-local_2015-1_all.deb

texlive-local の内容は、サンプル の通りです。

sphinx のインストール

手順は 日本語公式 の通りに行う。

$ sudo pip install sphinx

最新版を使いたかったので pip でインストールすることにした。

$ sphinx-build --version
Sphinx (sphinx-build) 1.3.1

doxygen のインストール

手っ取り早く動かしたいため、公式から Linux バイナリをダウンロードしてインストールすることに。

$ curl -LO ftp://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.10.linux.bin.tar.gz
$ tar zxvf doxygen-1.8.10.linux.bin.tar.gz
$ cd doxygen-1.8.10
$ ./configure --prefix /opt/toolchain/doxygen
  Checking for GNU install tool... using /usr/bin/install
  Created Makefile from Makefile.in...
$ sudo make install
/usr/bin/install -d /opt/toolchain/doxygen/bin
/usr/bin/install -d /opt/toolchain/doxygen/doc/doxygen
/usr/bin/install -m 755 bin/doxygen    /opt/toolchain/doxygen/bin
/usr/bin/install -m 755 bin/doxytag    /opt/toolchain/doxygen/bin
/usr/bin/install: cannot stat 'bin/doxytag': No such file or directory
make: *** [install] Error 1

なんと!公式のバイナリでインストール失敗してしまった。。。

解決方法を探してみたが、手順ミスではなさそう。どういうこと!?

調べてみたが、 doxytag は別に必要なさそうなので、インストール対象から外すことに。(ついでに、存在しない examples ディレクトリも外す)

$ diff -u Makefile.in.orig Makefile.in
$ diff -u Makefile.in.orig Makefile.in
--- Makefile.in.orig    2015-09-26 17:26:45.702458300 +0000
+++ Makefile.in 2015-09-26 17:29:11.238458300 +0000
@@ -2,7 +2,7 @@
        $(INSTTOOL) -d $(INSTALL)/bin
        $(INSTTOOL) -d $(INSTALL)/doc/doxygen
        $(INSTTOOL) -m 755 bin/doxygen    $(INSTALL)/bin
-       $(INSTTOOL) -m 755 bin/doxytag    $(INSTALL)/bin
+       #$(INSTTOOL) -m 755 bin/doxytag    $(INSTALL)/bin
        #$(INSTTOOL) -m 755 bin/doxywizard $(INSTALL)/bin
        cp -r html $(INSTALL)/doc/doxygen
-       cp -r examples $(INSTALL)/doc/doxygen
+       #cp -r examples $(INSTALL)/doc/doxygen

再度、インストールを行う。

### インストール先の設定を行う
$ ./configure --prefix /opt/toolchain/doxygen
$ sudo make install
### 環境変数にパスを通す
$ echo 'PATH="/opt/toolchain/doxygen/bin:$PATH"' >> ~/.profile
$ . ~/.profile
### 実行確認を行う
$ doxygen --version
1.8.10

RedPen のインストール

RedPen を動作させるには、 Java 実行環境が必要になるので、 Java からインストールする。

Java のインストール

手順は以下をを参考にしました。

UbuntuにJava8環境構築

$ sudo add-apt-repository ppa:webupd8team/java
$ sudo apt-get update
$ sudo apt-get install oracle-java8-installer

インストール中には、ライセンスやらオプションの確認が行われるので、回答する。

インストール後、(よくわからないが、)環境設定などを行ってくれるパッケージをインストールして完了となる。

$ sudo apt-get install oracle-java8-set-default
$ java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

本体のインストール

RedPen は Java 製ということで、バイナリをダウンロードしてコピーするだけのインストールになる。

GitHubのリリースページ から最新のバイナリをダウンロードする。

github.com

$ curl -LO https://github.com/redpen-cc/redpen/releases/download/v1.3.0/redpen-1.3.0.tar.gz
$ tar zxvf redpen-1.3.0.tar.gz
$ sudo cp -a redpen-distribution-1.3/ /opt/redpen
$ sudo chown root:root -R /opt/redpen/
$ JAVA_HOME=/usr/lib/jvm/java-8-oracle/jre redpen --version
1.3.0

これらのツールをうまく活用できれば、やりたいことに時間を使えるようになる。かもしれない。

とりあえずコンテナ作ってみる

試行錯誤のための環境づくり

まだ、 Docker には十分慣れていないので(そして、以前試した時よりだいぶバージョンが上がっているので)、試行錯誤用のコンテナを作成する。

このコンテナでインストール手順の確率や、破壊的な変更などを試してみる。

Dockerfile を作成する

Docker を使って、オリジナルのコンテナを作成する場合は、何はともあれ Dockerfile が必要になる。

作成にあたり、参考にしたのは以下のサイト。

とりあえず、以下の様なコンテナを作成してみた。

  • Ubuntu 14.04 ベース
  • apt コマンド使用可
  • SSHサーバあり
  • 開発環境( build-essential )あり

あとは、作成したコンテナの中で、ツールのビルド手順を確立していき、各コンテナの Dockerfile を作成していく。

#
# Dockerfile for Embryo Container.
#

# Pull base image.
FROM ubuntu:14.04

# Author.
MAINTAINER kenz_san

# Install packages.
RUN sed -i -e 's/\/\/archive.ubuntu.com/\/\/ftp.jaist.ac.jp/g' /etc/apt/sources.list && \
    apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y python-software-properties \
                                                      software-properties-common
RUN add-apt-repository -y ppa:git-core/ppa && \
    add-apt-repository -y ppa:mercurial-ppa/releases
RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential \
                                                      byobu \
                                                      curl \
                                                      git \
                                                      mercurial \
                                                      openssh-server \
                                                      python-dev \
                                                      python-setuptools \
                                                      python-pip \
                                                      python-virtualenv \
                                                      unzip \
                                                      vim \
                                                      wget
RUN curl -Lo /tmp/subversion_installer.sh http://opensource.wandisco.com/1.9/scripts/subversion_installer_1.9.sh && \
    echo yn | bash /tmp/subversion_installer.sh


# Create user.
RUN useradd -d /home/embryo -m -s /bin/bash embryo && \
    echo "embryo:embryo" | chpasswd && \
    echo "embryo ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
    echo -e "LANG='ja_JP.UTF-8'" > /etc/default/local

# Setup sshd.
RUN sed -i -e '/^UsePAM\s+yes/d' /etc/ssh/sshd_config && \
    mkdir -p /var/run/sshd && \
    /etc/init.d/ssh start && /etc/init.d/ssh stop && \
    sed -i 's/.*session.*required.*pam_loginuid.so.*/session optional pam_loginuid.so/g' /etc/pam.d/sshd

# Set environment variables.
ENV HOME /home/embryo

# Define working directory.
WORKDIR /home/embryo

# 
EXPOSE 22

# Define default command.
CMD ["/usr/sbin/sshd", "-D"]

こんな感じで。

開発に必要そうなパッケージは詰め込んで、SSH だけ有効にしている。

$ docker build -t kenz_san/embryo .
$ docker run -d -i -t -p 22:22 kenz_san/embryo

でコンテナが起動するので、 putty などで 22 ポートにアクセスすれば SSH サーバサーバに接続できる。

Ubuntu 14.04.3 の環境準備を行う

Ubuntu のインストール

Docker もインストールするつもりなので、 64bit 版であることは必須。

更に、GUIは要らないので、軽量化を重視して Server エディションをインストールしました。

とりあえず、言語は日本語で。(コンソールの表示は文字化けするけど、基本 SSH でアクセスするから関係ないよね!)

www.ubuntu.com

apt リポジトリを近場に切り替える

標準のままだと、海外のサーバに対してパッケージの取得などを行うため、ネットワーク速度がかなり遅い。

そこで、近場(日本国内)の安定したサーバにリポジトリを変更する。(今回は JAIST にした)

$ sudo sed -i".bak" -e 's/\/\/jp.archive.ubuntu.com/\/\/ftp.jaist.ac.jp/g' /etc/apt/sources.list

これで、 apt 操作は快適になる。

コアに必要なパッケージをインストールする

基本的な開発環境としての機能は、 Docker 上に構築するつもりなので、必要最低限のパッケージのみインストールする。

その前に、おもむろにアップデートする。

$ sudo apt-get update
$ sudo apt-get upgrade -y

何はともあれ、ネットワークディレクトリの準備

まずは、母艦からファイルにアクセスするために SAMBA 環境を構築する。

Docker でコンテナを動作させるときも、コード編集などのファイルアクセスについては、(コンテナの共有機能を使って) Docker を動作させている Ubuntu 上にだけアクセスすれば良いようにする。

複数のサービス(今回は SAMBA )をどう出させることはリソースの無駄なので、母艦のスペック上、冗長な処理は省いていく

Ubuntu Server インストール時に、追加インストールパッケージとして選択していたので、すでにパッケージはインストール済み。

まだ入っていない場合は、

$ sudo apt-get install -y samba

とすればインストールできるはず。

次に、 SAMBA で公開するディレクトリの設定を行う。(この辺りは、好みが分かれる設定だと思うので、他の人がどうするか気になります)

$ sudo vim /etc/samba/smb.conf
--- /etc/samba/smb.conf.orig 2015-09-13 09:36:50.780300850 +0900
+++ /etc/samba/smb.conf   2015-09-13 09:41:54.088300850 +0900
@@ -190,28 +190,29 @@
 # Un-comment the following (and tweak the other settings below to suit)
 # to enable the default home directory shares. This will share each
 # user's home directory as \\server\username
-;[homes]
-;   comment = Home Directories
-;   browseable = no
+[homes]
+   comment = Home Directories
+   browseable = no
 
 # By default, the home directories are exported read-only. Change the
 # next parameter to 'no' if you want to be able to write to them.
-;   read only = yes
+   read only = no
+   writable = yes
 
 # File creation mask is set to 0700 for security reasons. If you want to
 # create files with group=rw permissions, set next parameter to 0775.
-;   create mask = 0700
+   create mask = 0775
 
 # Directory creation mask is set to 0700 for security reasons. If you want to
 # create dirs. with group=rw permissions, set next parameter to 0775.
-;   directory mask = 0700
+   directory mask = 0775
 
 # By default, \\server\username shares can be connected to by anyone
 # with access to the samba server.
 # Un-comment the following parameter to make sure that only "username"
 # can connect to \\server\username
 # This might need tweaking when using external authentication schemes
-;   valid users = %S
+   valid users = %S
 
 # Un-comment the following and create the netlogon directory for Domain Logons
 # (you need to configure Samba to act as a domain controller too.)
@@ -234,23 +235,23 @@
 ;   create mask = 0600
 ;   directory mask = 0700
 
-[printers]
-   comment = All Printers
-   browseable = no
-   path = /var/spool/samba
-   printable = yes
-   guest ok = no
-   read only = yes
-   create mask = 0700
+;[printers]
+;   comment = All Printers
+;   browseable = no
+;   path = /var/spool/samba
+;   printable = yes
+;   guest ok = no
+;   read only = yes
+;   create mask = 0700
 
 # Windows clients look for this share name as a source of downloadable
 # printer drivers
-[print$]
-   comment = Printer Drivers
-   path = /var/lib/samba/printers
-   browseable = yes
-   read only = yes
-   guest ok = no
+;[print$]
+;   comment = Printer Drivers
+;   path = /var/lib/samba/printers
+;   browseable = yes
+;   read only = yes
+;   guest ok = no
 # Uncomment to allow remote administration of Windows print drivers.
 # You may need to replace 'lpadmin' with the name of the group your
 # admin users are members of.

さらに、ユーザの作成も行います。

$ sudo smbpasswd -a <ユーザ名>
New SMB Password: <パスワード>
Retype new SMB Password: <パスワード>

設定変更後は、 SAMBA の再起動が必要です。

$ sudo service smbd restart

Docker をインストールする

基本的な手順は、 公式 の通りにすれば良い。

$ curl -sSL https://get.docker.com/ | sh

あれ?1.3の頃と比べて、格段に簡単になってる。

インストールが完了すると、

$ sudo usermod -aG docker <ユーザ名>

と表示されるので実行しておく。( sudo しなくても docker コマンドが使用できるようになる)

以前は、

$ sudo gpasswd -a <ユーザ名> docker
Adding user <ユーザ名> to group docker

としていたけど、同じ効果となる。

とりあえず、 VirtualBox 上で直接動作する Ubuntu については以上で設定終わり。(不足が見つかったら加筆します)