グレインの備忘録

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

NeomakeでC++の自動構文チェックをやらせてみる

Vimで自動構文解析といえばsyntasticだったが、チェック中は動作をブロックしてしまうので微妙だった。

NeoVimではリモートプラグインが導入され、このような問題を解決できるものが登場したので使ってみる。

NeoMakeを入れる

github.com

今回使うのはこのNeoMakeというもの。

構文チェックだけでなく、いわゆるmakeコマンドの代わりもしてくれるらしい。

インストールは、tomlに

[[plugins]]
repo = 'neomake/neomake'
hook_post_source = '''
    autocmd! BufWritePost * Neomake
'''

と書く。保存時に:Neomakeを実行するのは、syntasticの時と同じで自動補完は実行してくれないから。

使い方

使い方というほどのこともないが、普通にソースを開いて「:Neomake」を実行すれば良い。

Ubuntu16.04にTex環境を整える

LaTeXを使ってみたかったのでUbuntuに入れてみた。

基本苦労することはなかったが入れ方を一応メモ。

インストール手順

必要なのは、

の二つ。

Ubuntuの場合は

$ sudo apt -y install texlive texlive-lang-japanese

で済む。

使い方

まずは入門サイトなど参考にTeX文書を作る。

LaTeX入門 - TeX Wiki

完成したら保存する。

コンパイル

例えば「test.tex」に保存したとすると、

$ platex test

でdviファイルが生成される。

あとはこれをpdfに変換すればいいので、

$ dvipdfmx test.dvi

でpdfが生成される。

若しくは、一発でpdfに変換するには

$ ptex2pdf -l test

とすればよい。

Cmake+Ninjaでビルドをやってみる

最近プログラムをビルドするのにCmakeを使い始めてみた。

Cmakeでは、軽量な動作で有名なNinja用のファイルを生成できるらしいので試してみる。

Ninjaのインストール 同名のパッケージにご用心

早速入れてみようと、安直に以下のコマンドを実行。

$ sudo apt -y install ninja

ところが、

$ cmake . -G Ninja

とするとエラーが。

-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler using: Ninja
CMake Error:
  The detected version of Ninja (0.1.3) is less than the version of Ninja required
  by CMake (1.3).


CMake Error: Internal CMake error, TryCompile generation of cmake failed
-- Check for working C compiler using: Ninja -- broken

バージョンが古くて怒られている模様。確かに、

$ ninja --version
log: ninja version 0.1.3 initializing

と出るので、バージョンが低いらしい。apt提供のパッケージが古いのか?と思い

$ apt search ninja

とすると、

ninja/xenial,now 0.1.3-2 amd64 [インストール済み]
  GNU/Linux 用特権昇格検知システム

ninja-build/xenial,now 1.5.1-0.1ubuntu1 amd64 
  small build system closest in spirit to Make

ninja-build-doc/xenial,xenial 1.5.1-0.1ubuntu1 all
  documentation for ninja-build

ninja-ide/xenial,xenial 2.3-2 all
  integrated development environment (IDE) for Python

と出てきた。どうやらさっきのninjaはビルドツールではなかったらしい。

気を取り直して

$ sudo apt -y remove ninja
$ sudo apt -y install ninja-build

として入れなおす。これでうまく行くだろう。

ツールチェインの切り替えにご注意

ところが、

$ cmake . -G Ninja
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler using: Ninja
CMake Error:
  The detected version of Ninja () is less than the version of Ninja required
  by CMake (1.3).


CMake Error: Internal CMake error, TryCompile generation of cmake failed
-- Check for working C compiler using: Ninja -- broken

またもやエラー。今度はバージョンが検出されていない模様。

調べてみると、以下のページに行き当たった。

github.com

以下引用

"if previously build dir already configured , but ninja executable is moved, cmake didn't report command not found ,but reports "The detected version of Ninja ("") is less than the version of Ninja required by CMake ("1.3") which is confused."

要するに、残骸が残っているとダメということらしい。ということで、

$ rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile
$ cmake . -G Ninja

というふうに残骸を消してやるとうまく行った。

確かに軽量だが出力がログみたいに残らずに消えてしまうのが少し残念かもしれない。

リンクが倍速くなるらしい「lld」を試す

最近、ビルトインのldによるリンクの遅さが気になってきた。

そこで、もっと高速なリンク方法がないか探してみたところ、いくつかの新しいリンカに辿り着いた。

GNU goldよりも2倍早いlld

高速なリンカとしてはGNU goldが割と有名らしいが、それよりも更に高速なlldというものを見つけた。

https://lld.llvm.org/

このページ曰く「GNU goldの2倍高速で」動作するらしい。

lldのインストール

Ubuntu 16.04 (Xenial Xerus) にはパッケージがあるようなので入れてみる

sudo apt -y install lld-4.0

これでld.lldが利用可能になる。

ついでに、ldのシンボリックリンク切り替えの設定もしておく。

参考: qiita.com

sudo update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld" 30
sudo update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.gold" 20
sudo update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.bfd" 10

これで登録は完了で、あとは

sudo update-alternatives --config ld

とすることでldの切り替えができる。

実際に使ってみた感じとしてはやはり数倍早くなっている感じだ。
少し待たされるようなジョブも一瞬で終わるようになった。
おそらくconfigureの速度を大きく改善するであろう。

構造体のDictionaryでは直接値を変更できない

コンテナの返値が値型か参照型かに気をつけましょうねという話。

シチュエーション

例えば、以下のようなコードを書いてみたとする。

public class Program
{
    struct MyStruct
    {
        public int val1;
        public int val2;
    }
    
    public static void Main()
    {
        var dic = new Dictionary<int, MyStruct>();
        
        dic[0].val1 = 1;
        dic[0].val2 = 2;
    }
}

自前の構造体をDictionaryに格納し、その値を変更するコードである。

しかし、これはコンパイルエラーになる。

error CS1612: 変数ではないため、'Dictionary.this[int]' の戻り値を変更できません

Dictionary内の要素に値を代入することができていないようだ。

dic[0]の返値は参照型ではなく値型

実は、これはMyStructが値型であることが原因である。

つまり、dic[0]というのは、dic内の0番目の要素のコピーであって、それに対していかなる操作を行ってもdic内の要素には一切影響しない。

上記のように[]で参照したものの値を直接書き換えたいならば、MyStructをclassにするしかない。

public class Program
{
    class MyStruct
    {
        public int val1;
        public int val2;
    }
    
    public static void Main()
    {
        var dic = new Dictionary<int, MyStruct>();
        
        dic.Add(0, new MyStruct());

        dic[0].val1 = 1;
        dic[0].val2 = 2;
    }
}

これならdic[0]はdic内の0番目の要素への参照となり、正しく動く。


C++ならコンテナは必ず参照型を返してくれるので、原因が分かるのに時間がかかった。

コンテナのイテレータを保持するのは避けよう

STLとかのコンテナが吐き出すイテレータをポインタ代わりに持っとくのはやめましょうねというお話。

コンテナへの非const操作はイテレータを破壊する(可能性がある)

「可能性がある」だから余計厄介だったりする。

テストケースではうまく動いても実環境では動かなかったり。

詳しい話はこちらのページに投げさせていただく。

qiita.com

neosnippetに自分のスニペットを追加する

前回の記事ではneosnippetを導入したが、自作のスニペットを使いたくなったので方法をメモ。

neosnippetの設定

まずは、スニペットファイルの保存先を指定する。

プラグイン起動時の設定に一行追加する。

let g:neosnippet#snippets_directory = ~/.vim/dein/repos/github.com/Shougo/neosnippet-snippets/snippets/'

したら再起動する。

スニペットの編集

まずは、スニペットを追加したいタイプのファイルを開く。

そして、「:NeoSnippetEdit」とコマンドを入力する。

すると、スニペットの編集画面が開く。

スニペットの構文は以下の通り。

snippet [識別子]
alias [略記法]
<インデント>スニペット内容
<インデント>スニペット内容
…

スニペット内容は基本は展開したい内容をそのまま書く。

また、Ctrl+Kで順にカーソルが移動できるような場所は「${数字:デフォルト値}」として書けばよい。

終わったら「:w」で保存する。


以上でスニペットの追加は完了である。