グレインの備忘録

プログラミング関係とかをつらつらと。

C++補完用にdeoplete-clangを導入する

コードを書くにはやっぱり補完がないと辛い。

C++をNeoVimで書くならdeoplete-clangがベストチョイスのようだ。

導入

deopleteはNeoVimのRemotePlugin機能を使うのでpython-clientを入れておく必要がある。

以下のコマンドでインストールできる。

sudo apt -y install python3-pip
pip3 install neovim

次はプラグイン導入。

init.vimに以下を追加する。

call dein#begin()
"(中略)
call dein#add('Shougo/deoplete.nvim')
call dein#add('zchee/deoplete-clang')
"(中略)
call dein#end()

"deoplete settings
let g:deoplete#sources#clang#libclang_path = '/usr/lib/llvm-3.8/lib/libclang-3.8.so.1'
let g:deoplete#sources#clang#clang_header = '/usr/include/clang'

続いて、インストール作業。

:call dein#install()
:UpdateRemotePlugins

これで正しくdeoplete及びdeoplete-clangがインストールされた。

所感

f:id:grainrigi:20170827133758p:plain

外部ライブラリのヘッダ等もちゃんと解析している模様。

Intellisenseとも遜色なく、十分に使い勝手が良いと思う。

ただ、#includeディレクティブそのものの補完はしないのでneoincludeも組み合わせるといいだろう。

基本的なGitコマンドチートシート

初期設定など

ユーザー設定(氏名とメアド)

git config --global user.name "Grain"
git config --global user.email grain@exout.net

–globalによって設定が永続化する。

リポジトリ作成

対象フォルダにて

git init

コミット関連

ファイルのステージ

git add <file>..

ステージ内容の確認

git status

コミット

git commit -m "<comment>"

リモート関連

リモートリポジトリの追加

git remote add <reponame> <url>

reponameは普通originにする。

プッシュ

git push -u <reponame> <branch> (初回)
git push (2回目以降)

-uオプションはリポジトリとブランチを記憶する。

プル

git pull <reponame> <branch>

クローン

git clone <url> <dir>

認証情報の保存設定

パスワードを保存しておく設定は以下。

git config --global credential.helper store

プレーンテキストで保存されるので注意する。

ブランチ関連

ブランチ(作成)

git branch <branchname>

チェックアウト(切り替え)

git checkout <branchname>

※ブランチ作成後はチェックアウトして切り替える必要がある

マージ

git merge <commit>

※マージ先にチェックアウトしてから、マージ元のコミットを指定する

ブランチ削除

git branch -d <branchname>

とりあえずこんなところか。必要になればまた追加

C++用のMakefileを半自動で書く

Makefileはうまく書けばコンパイルが自動化できて楽だが、ソースの登録が面倒くさい。

そこで、シェルスクリプトなどを活用して自動でMakefileを書いてみる。

(autoconfとかを使ってもいいのだけど、小規模なプログラムでいちいちconfigureするのも面倒だし。)

まずはベタ書き

以下のようなシチュエーションを考える。(treeで出力したディレクトリ構造)

.
├── Makefile
├── src
│   ├── main.cpp (test1_1.h,test2.hをインクルード)
│   ├── test1.cpp (test1_1.h,test1_2.hをインクルード)
│   ├── test1_1.h
│   ├── test1_2.h
│   ├── test2.cpp (test2.hをインクルード)
│   └── test2.h
└── [test]を出力(バイナリ)

とりあえず手動で全部書いてみる。

CXX := clang
CXXFLAGS := -Wall -std=c++11
LD := clang
LDFLAGS := -lstdc++

TARGET := test
OUTS := main.o test1.o test2.o
SRCDIR := src


#本体生成規則
$(TARGET) : $(OUTS:%=$(SRCDIR)/%)
  $(LD) $^ -o $@ $(LDFLAGS)

#依存関係
main.o : $(SRCDIR)/main.cpp $(SRCDIR)/test1_1.h $(SRCDIR)/test2.h
test1.o : $(SRCDIR)/test1.cpp $(SRCDIR)/test1_1.h $(SRCDIR)/test1_2.h
test2.o : $(SRCDIR)/test2.cpp $(SRCDIR)/test2.h

#サフィックスルール
.cpp.o :
  $(CXX) -c $< -o $@ $(CXXFLAGS)

ヘッダの依存関係などを考慮すればこういう風に書くことになるだろうか。(流石に少し醜い部分もあるが・・・)

サフィックスルールなどを使って楽してはいるが、依存関係を自分で調べないといけないのがだるい。

ソース数が少ないうちはこれでも我慢できるが、やはり数が増えるとつらい。

ヘッダ依存関係の自動検出

実はgccやclangにはMakefile用の便利な機能がある。

ソースファイルを与えるとそれが依存しているソースとヘッダをmakefile形式で列挙してくれるのだ。

例えば、

clang -MM src/test1.cpp

と実行すると、

test1.o: src/test1.cpp src/test1_1.h src/test1_2.h

と言った具合に出力され、非常に便利である。

ヘッダファイルの中で更にインクルードがあってもきちんと追跡してくれる。

これをうまく活用してみることにする。

シェルスクリプトによるソースの列挙

ソースごとの依存関係が自動で検出できるなら後は簡単で、

シェルスクリプトで1ファイルずつ出力してしまえばよい。

ついでにソースコードの一覧も生成してしまおう。

#!/bin/bash

#出力ファイル:
#    Makefile.1 : 依存関係一覧
#    Makefile.2 : ソース一覧

export MK_DEPENDS=Makefile.1
export MK_SOURCES=Makefile.2
export SRCDIR=src
export SUFFIX="*.cpp"
export CXX=clang

#Makefileの初期化
echo -n > $MK_DEPENDS
echo -n "SRCS := " > $MK_SOURCES

#SRCDIR直下の全cppファイルに対して操作する
find $SRCDIR -name $SUFFIX | while read -r f; do
    #依存関係を出力
    $CXX -MM $f >> $MK_DEPENDS
    #ソース一覧に追加
    echo -n "$f " >> $MK_SOURCES
done

#ソース一覧に改行を追加
echo >> $MK_SOURCES

とりあえず「makedepends.sh」として保存しておく。

これを実行すると、

[Makefile.1]
main.o : src/main.cpp src/test1_1.h src/test2.h
test1.o : src/test1.cpp src/test1_1.h src/test1_2.h
test2.o : src/test2.cpp src/test2.h
[Makefile.2]
SRCS := src/main.cpp src/test1.cpp src/test2.cpp

といった具合になる。(順番は異なる可能性がある)

リストをMakefileに取り込む

リストが生成できたので、あとはMakefileに取り込めば終わりだ。

CXX := clang
CXXFLAGS := -Wall -std=c++11
LD := clang
LDFLAGS := -lstdc++

MK_DEPENDS := Makefile.1
MK_SOURCES := Makefile.2

-include $(MK_SOURCES)

TARGET := test
#$(SRCS)の.cppを.oに変換して格納
OUTS := $(SRCS:%.cpp=%.o)

#本体生成規則
$(TARGET) : $(OUTS)
  $(LD) $^ -o $@ $(LDFLAGS)

#依存関係
-include $(MK_DEPENDS)

#サフィックスルール
.cpp.o :
  $(CXX) -c $< -o $@ $(CXXFLAGS)

これを保存してmakeすると、最初のMakefileと同様に正しくコンパイルされる。

makedepends.shも自動で実行

今のままだと、コンパイル前にmakedepends.shも実行しないといけないので何かと面倒だ。

そこで、makedepends.shも自動実行するようにしてみよう。

インクルードされたファイルを更新してから再実行する必要があるので少し工夫が必要だが、再帰をうまく使えばできる。

Makefileを以下のように書き換える。

CXX := clang
CXXFLAGS := -Wall -std=c++11
LD := clang
LDFLAGS := -lstdc++

MK_DEPENDS := Makefile.1
MK_SOURCES := Makefile.2
SH_MKDEPENDS := makedepends.sh

-include $(MK_SOURCES)

TARGET := test
#$(SRCS)の.cppを.oに変換して格納
OUTS := $(SRCS:%.cpp=%.o)
SRCDIR := src


#デフォルト生成規則
#makedependを実行し、test_implを生成する
$(TARGET) : $(OUTS) mkdep
  $(MAKE) target_impl

#実際のバイナリ生成
target_impl : $(OUTS)
  $(LD) $(OUTS) -o $(TARGET) $(LDFLAGS)

#依存関係
-include $(MK_DEPENDS)

#サフィックスルール
.cpp.o :
  $(CXX) -c $< -o $@ $(CXXFLAGS)

#コマンド一覧
.PHONY : clean mkdep

clean :
  find $(SRCDIR) -name "*.o" | while read -r f; do rm -f $$f; done
  rm -f 

mkdep :
  bash $(SH_MKDEPENDS)

これで最終形態になるのでついでにcleanも付けておいた。

※ここのMakefileをコピペするときには生成規則行頭のスペースをタブに変換すること

これでかなり楽にコンパイルができそうだ。

(プロジェクト依存の部分のみを別ファイルに切り出すと更に便利かもしれない。)

lightline対応のカラースキーム "tender" を試す

以前lightlineを使ってステータスラインを格好良くしたが、このlightlineに対応した良さげなカラースキームがあったので試してみた。

tenderの導入

いつもどおりサクッと。

call dein#add('jacoborus/tender.vim')

をvimrcに追加して

:call dein#install()

でインストール。

更にvimrcに設定追加

"tender settings
if (has("termguicolors"))
    set termguicolors
endif                                                                              
let g:cpp_class_scope_highlight = 1                                                
colorscheme tender 

以上で完了。

f:id:grainrigi:20170827010141p:plain

色は控え目で、個人的にはなかなか気に入っている。

lightlineを使ってステータスバーを格好良くする

lightlineとは

lightlineはVimプラグインで、ステータスバーを格好良くできる。

変更前

f:id:grainrigi:20170827003513p:plain

変更後

f:id:grainrigi:20170827003528p:plain

また、この手のプラグインの中では取り回しのしやすい方らしい。lightline.vim作りました - プラグインの直交性について

導入

とりあえずpluginを入れる。

vimrcに一行追加

call dein#add('itchyny/lightline.vim')

インストールする。

:call dein#install()

あとは再起動すれば反映される。

その他設定

設定はすべてg:lightlineに設定する。

例: ステータスバーにファイルタイプ・エンコードも表示する

let g:lightline = {
      \ 'active': {
      \   'right': [ [ 'lineinfo' ],
      \              [ 'percent' ],
      \              [ 'fileformat', 'fileencoding', 'filetype' ] ]
      \ }

カラースキームを用いたり他のプラグインと連携したりと言ったことも可能。

詳細はgitレポジトリや本人のブログを参照されたし。

Ubuntu 16.04のapt updateでappstreamcliがクラッシュする

Ubuntu 16.04をインストールした直後に

sudo apt -y update

とするとなぜかAbortする。

どうやらappstreamcliがクラッシュしているらしい。

一旦appstreamcliを無効にする

調べたらドンピシャの記事があった。

ubuntu-16-04のapt-updateでappstreamcliが固まる

appstreamcliを無効にしてから実行するとうまくいった。

#appstreamを無効化
sudo killall -KILL apt.systemd.daily
sudo mv /etc/apt/apt.conf.d/50appstream /etc/apt/apt.conf.d/50appstream.disable
#apt update/upgrade
sudo apt update -y
sudo apt upgrade -y
#appstreamを有効化して再度update
sudo mv /etc/apt/apt.conf.d/50appstream.disable /etc/apt/apt.conf.d/50appstream
sudo apt update -y

一度うまくいくと再度有効にしても平気らしい。

VMWareでの激重を解消

Windows上でLinuxを使うならやはり仮想化が一番。

しかし、VMWare上でUbuntuを走らせるとどうにも動作がもっさりしている。

いったい何が原因なのか。

vmemへの書き込みをやめさせる

色々調べてみると、vmemにスワップとしてデータを書き込んでいるのが悪いらしい。

VMware Player 上の仮想OSを高速化させ軽快に作動させるチューニング

メモリに余裕がある環境ならスワップなど必要ないので無効化する。

・.vmxに次の行を追加

MemTrimRate = "0"
mainMem.useNamedFile= "FALSE"
sched.mem.pshare.enable = "FALSE"
prefvmx.useRecommendedLockedMemSize = "TRUE"
MemAllowAutoScaleDown = "FALSE"

追加して再起動すると、動作は幾分か軽快になった。

ただし、メモリ使用量も固定になってしまうようだ。