GCC
shell
clang
coding

コンパイル用shell script C版(clangとgcc)とC++版(clang++とg++)

コンパイル用shell scriptを記述する。
ここではCERT Cの例題を編纂(compile)・実行する方法を検討する。shell scriptのデバッグは苦手。なるべく簡単な機能だけ使う。

最終的にはmakeを作るかもしれない。makeのデバッグはもっと苦手。全部が完成したら作成予定。

引数に関する考察

1コンパイル対象ファイル
1.1 C用 .cを付加
1.2 c++用 .cppを付加

2 複数ファイルのコンパイル
2.1 2つファイル用
2.2 3つファイル用

3 コンパイルオプションの指定
ファイル名の後に、コンパイルオプションを記述

4 実行時のオプションの記述
最後の引数は実行時に用いる

まずは、下記に掲載するプログラム用。

CERT C入門(1) Rule 01. Preprocessor (PRE)
https://qiita.com/kaizen_nagoya/items/8d2cb4158ed53d5a0a28

C言語の断片を、できれば実行結果で何か出力する処理を入れる。
 コンパイルに意味があるかどうかを確かめる。
  (意味のない処理がどういう記述であってもどうでもいい。)
 副作用の有無を確かめるには出力するのが一番。
  (出力しようとしなければ副作用が生じないこともある。)
 実行結果に違いがあるかどうかを確かめる。
  (コンパイラによって違うがあるような出力を試す。)

これまでに類似の作業は、「C Puzzle Book」「国際規格C、C++」「MISRA C/MISRA C++」で行ってきた。

C Puzzle Bookの有り難み5つ、C言語規格及びCコンパイラの特性を認識
https://qiita.com/kaizen_nagoya/items/d89a48c1536a02ecdec9

[C][C++]の国際規格案の例題をコンパイルするときの課題7つ。
https://qiita.com/kaizen_nagoya/items/5f4b155030259497c4de

MISRA C まとめ #include
https://qiita.com/kaizen_nagoya/items/f1a79a7cbd281607c7c9

Cコンパイル

cert0.sh
cc pre01n.c
./a.out

実行可能に

$ chmod +x cert0.sh

+xで実行権を付与。数字を打つより間違いが少ない。

初心者向けシェルスクリプトの基本コマンドの紹介
https://qiita.com/zayarwinttun/items/0dae4cb66d8f4bd2a337

実行

$ ./cert0.sh
$ 3 3

コンパイルして実行する

引数

引数を渡す

cert1.sh
cc $1
./a.out

引数渡し実行

$ cert1 pre1n.c
$ 3 3

複数のコンパイラを使う

cert1.sh
cc $1
./a.out
gcc-6 $1
./a.out

課題、2つ目のコンパイルを失敗すると、1つ目をまた実行してしまう。誤解する可能性あり。

$ cert1 pre1n.c
$ 3 3
$ 3 3

実行結果を削除する

cert1.sh
cc $1
./a.out
rm a.out
gcc-6 $1
./a.out
rm a.out

事前の実行結果を削除

1つ目のコンパイルを失敗した場合、何かの結果を実行してしまう。

cert1.sh
rm a.out
cc $1
./a.out
rm a.out
gcc-6 $1
./a.out
rm a.out

実行ファイルを残す

cert2.sh
cc $1.c -o $1l
./$1l
gcc-6 $1.c -o $1g
./$1g

".c"の入力を省略できるようにした。

すごくスッキリした。

実行すると

$ cert2 pre1n
$ 3 3
$ 3 3

どちらがどちらの実行結果が間違えるといけない。

処理内容表示

cert2.sh
echo "clang/llvm $1.c"
cc $1.c -o $1l
./$1l
gcc-6 $1.c -o $1g
./$1g

実行して見ると

$ cert2 pre1n
clang/llvm pre32n.c
3 3
gcc-6 pre32n.c
3 3

1日目のシェルスクリプト作りはこの辺まで。
のつもりでいたら、certc側で、第二引数を渡す必要があるプログラムがあり、書き換え。コンパイルエラー時には実行しないように追記。

certc3.sh
#!/bin/sh
echo "$ clang $1.c"
cc $1.c -o $1l
if [  -e $1l ]; then
./$1l $2
fi
echo "\r"
echo "$ gcc-6 $1.c"
gcc-6 $1.c -o $1g
if [  -e $1g ]; then
./$1g $2
fi

gcc-7対応

clg7.sh
#!/bin/sh
echo "$ clang $1.cpp"
cc $1.c -o $1l -I.
if [  -e $1l ]; then
./$1l $2
fi
echo "\r"
echo "$ gcc-7 $1.cpp"
gcc-7 $1.c -o $1g -I.
if [  -e $1g ]; then
./$1g $2
fi

gcc-7対応コンパイル対象が2つある場合

clg72.sh
#!/bin/sh
echo "$ clang $1.c"
cc $1.c $2.c -o $1l -I.
if [  -e $1l ]; then
./$1l $3
fi
echo "\r"
echo "$ gcc-7 $1.c"
gcc-7 $1.c $2.c -o $1g -I.
if [  -e $1l ]; then
./$1l $3
fi

gcc-7対応コンパイル対象が3つある場合

clg73.sh
#!/bin/sh
echo "$ clang $1.c"
cc $1.c $2.c $3.c -o $1l -I.
if [  -e $1l ]; then
./$1l $4
fi
echo "\r"
echo "$ gcc-7 $1.c"
gcc-7 $1.c $2.c $3.c -o $1g -I.
if [  -e $1g ]; then
./$1g $4
fi

C++用作成

certcpp.sh
#!/bin/sh
echo "$ clang++ $1.cpp"
clang++ $1.cpp -o $1l
if [  -e $1l ]; then
./$1l $2
fi
echo "\r"
echo "$ g++-6 $1.cpp"
g++-6 $1.cpp -o $1g
if [  -e $1g ]; then
./$1g $2
fi

g++-7対応

cppgl.sh
#!/bin/sh
echo "$ clang++ $1.cpp"
clang++ $1.cpp  -o $1l
if [  -e $1l ]; then
./$1l $2
fi
echo "\r"
echo "$ g++-7 $1.cpp"
g++-7 $1.cpp -o $1g
if [  -e $1g ]; then
./$1g $2
fi

-std=c++17 追記

cppgl17.sh
#!/bin/sh
echo "$ clang++ $1.cpp"
clang++ $1.cpp  -std=c++17  -o $1l
if [  -e $1l ]; then
./$1l $2
fi
echo "\r"
echo "$ g++-7 $1.cpp"
g++-7 $1.cpp -std=c++17  -o $1g
if [  -e $1g ]; then
./$1g $2
fi

-Wallをつけた。一通りコンパイルしてみた。改良点を探すために-Wallの警告を順次確認。

cppwa17.sh
#!/bin/sh
echo "$ clang++ $1.cpp -std=c++17 -Wall"
clang++ $1.cpp -std=c++17 -Wall -o $1l
if [  -e $1l ]; then
./$1l $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++17  -Wall" 
g++-7 $1.cpp  -std=c++17 -Wall -o $1g
if [  -e $1g ]; then
./$1g $2
fi

-trigraph用にコンパイルオプションを記述できるようにした版(c++2011用)

cppwa11.sh
#!/bin/sh
echo " usege ./cppwa11.sh prog option msg"
echo "$ clang++ $1.cpp $2 -std=c++11 -Wall"
clang++ $1.cpp -std=c++11 $2  -Wall -o $1l
if [  -e $1l ]; then
./$1l $3
fi
echo "\r"
echo "$ g++-7 $1.cpp $2 -std=c++11  -Wall" 
g++-7 $1.cpp  -std=c++11 $2 -Wall -o $1g
if [  -e $1g ]; then
./$1g $3
fi

利用方法

./cppwa11 cpp2011-2-4 -trigraph
cppall.sh
#!/bin/sh
echo "$ clang++ $1.cpp -std=c++03 -Wall"
clang++ $1.cpp -std=c++03 -Wall -o $1l03
if [  -e $1l03 ]; then
./$1l03 $2
fi
echo "$ clang++ $1.cpp -std=c++11 -Wall"
clang++ $1.cpp -std=c++11 -Wall -o $1l11
if [  -e $1l11 ]; then
./$1l11 $2
fi
echo "$ clang++ $1.cpp -std=c++17 -Wall"
clang++ $1.cpp -std=c++17 -Wall -o $1l17
if [  -e $1l17 ]; then
./$1l17 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++03  -Wall"
g++-7 $1.cpp  -std=c++03 -Wall -o $1g03
if [  -e $1g03 ]; then
./$1g03 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++11  -Wall"
g++-7 $1.cpp  -std=c++11 -Wall -o $1g11
if [  -e $1g11 ]; then
./$1g11 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++17  -Wall" 
g++-7 $1.cpp  -std=c++17 -Wall -o $1g17
if [  -e $1g17 ]; then
./$1g17 $2
fi

docker用に追記

cppall.sh
#!/bin/sh
echo "$ clang++ $1.cpp -std=c++03 -Wall"
clang++ $1.cpp -std=c++03 -lc++ -I/usr/local/include/c++/7.3.0 -I/usr/local/include/c++/7.3.0/x86_64-linux-gnu -Wall -o $1l03
if [  -e $1l03 ]; then
    ./$1l03 $2
fi
echo "$ clang++ $1.cpp -lc++ -std=c++11  -Wall"
clang++ $1.cpp -std=c++11 -lc++ -I/usr/local/include/c++/7.3.0 -I/usr/local/include/c++/7.3.0/x86_64-linux-gnu -Wall -o $1l11
if [  -e $1l11 ]; then
    ./$1l11 $2
fi
echo "$ clang++ $1.cpp -lc++ -std=c++17  -Wall"
clang++ $1.cpp -std=c++17 -lc++ -I/usr/local/include/c++/7.3.0 -I/usr/local/include/c++/7.3.0/x86_64-linux-gnu -Wall -o $1l17
if [  -e $1l17 ]; then
    ./$1l17 $2
fi
echo "\r"
echo "$ g++ $1.cpp -std=c++03  -Wall"
g++ $1.cpp  -std=c++03 -Wall -o $1g03
if [  -e $1g03 ]; then
    ./$1g03 $2
fi
echo "\r"
echo "$ g++ $1.cpp -std=c++11  -Wall"
g++ $1.cpp  -std=c++11 -Wall -o $1g11
if [  -e $1g11 ]; then
    ./$1g11 $2
fi
echo "\r"
echo "$ g++ $1.cpp -std=c++17  -Wall" 
g++ $1.cpp  -std=c++17 -Wall -o $1g17
if [  -e $1g17 ]; then
    ./$1g17 $2
fi

-std=c++14を追加した版

cppall.sh
#!/bin/sh
echo "$ clang++ $1.cpp -std=c++03 -Wall"
clang++ $1.cpp -std=c++03 -I=. -Wall -o $1l03
if [  -e $1l03 ]; then
./$1l03 $2
fi
echo "$ clang++ $1.cpp -std=c++11 -Wall"
clang++ $1.cpp -std=c++11 -I=. -Wall -o $1l11
if [  -e $1l11 ]; then
./$1l11 $2
fi
echo "$ clang++ $1.cpp -std=c++14 -Wall"
clang++ $1.cpp -std=c++14 -I=. -Wall -o $1l14
if [  -e $1l14 ]; then
./$1l14 $2
fi
echo "$ clang++ $1.cpp -std=c++17 -Wall"
clang++ $1.cpp -std=c++17 -I=. -Wall -o $1l17
if [  -e $1l17 ]; then
./$1l17 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++03  -Wall"
g++-7 $1.cpp  -std=c++03 -I=. -Wall -o $1g03
if [  -e $1g03 ]; then
./$1g03 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++11  -Wall"
g++-7 $1.cpp  -std=c++11 -I=. -Wall -o $1g11
if [  -e $1g11 ]; then
./$1g11 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++14  -Wall"
g++-7 $1.cpp  -std=c++14 -I=. -Wall -o $1g14
if [  -e $1g14 ]; then
./$1g14 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++17  -Wall" 
g++-7 $1.cpp  -std=c++17 -I=. -Wall -o $1g17
if [  -e $1g17 ]; then
./$1g17 $2
fi

C++N4741はclang++ -std=c++2a

のc1.shでコンパイルエラーを確認。
cpla.shで2つのコンパイラの合計5つのオプション

c1.sh
#!/bin/sh
echo "$ clang++ $1.cpp  -std=c++2a -Wall"
clang++ $1.cpp -std=c++2a -I=. -Wall -o $1l2a
if [  -e $1l2a ]; then
./$1l2a $2
rm $1l2a
fi

コンパイル対象が2つの場合

c2.sh
#!/bin/sh
echo "$ clang++ $1.cpp $2.cpp -std=c++2a -Wall"
clang++ $1.cpp $2.cpp -std=c++2a -I=. -Wall -o $1l2a
if [  -e $1l2a ]; then
./$1l2a $3
rm $1l2a
fi
c3.sh
#!/bin/sh
echo "$ clang++ $1.cpp $2.cpp $3.cpp -std=c++2a -Wall"
clang++ $1.cpp $2.cpp $3.cpp -std=c++2a -I=. -Wall -o $1l2a
if [  -e $1l2a ]; then
./$1l2a $4
rm $1l2a
fi

2種類のコンパイラ、合計5種類のスイッチ

spla.sh
#!/bin/sh
echo "$ clang++ $1.cpp -std=c++03 -Wall"
clang++ $1.cpp -std=c++03 -I=. -Wall -o $1l03
if [  -e $1l03 ]; then
./$1l03 $2
fi
echo "$ clang++ $1.cpp -std=c++17 -Wall"
clang++ $1.cpp -std=c++17 -I=. -Wall -o $1l17
if [  -e $1l17 ]; then
./$1l17 $2
fi
echo "$ clang++ $1.cpp -std=c++2a -Wall"
clang++ $1.cpp -std=c++2a -I=. -Wall -o $1l2a
if [  -e $1l2a ]; then
./$1l2a $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++03  -Wall"
g++-7 $1.cpp  -std=c++03 -I=. -Wall -o $1g03
if [  -e $1g03 ]; then
./$1g03 $2
fi
echo "\r"
echo "$ g++-7 $1.cpp -std=c++17  -Wall" 
g++-7 $1.cpp  -std=c++17 -I=. -Wall -o $1g17
if [  -e $1g17 ]; then
./$1g17 $2
fi
cpla2.sh
#!/bin/sh
echo "$ clang++ $1.cpp $2.cpp -std=c++03 -Wall"
clang++ $1.cpp $2.cpp -std=c++03 -I=. -Wall -o $1l03
if [  -e $1l03 ]; then
./$1l03 $3
fi
echo "$ clang++ $1.cpp $2.cpp -std=c++17 -Wall"
clang++ $1.cpp $2.cpp -std=c++17 -I=. -Wall -o $1l17
if [  -e $1l17 ]; then
./$1l17 $3
fi
echo "$ clang++ $1.cpp $2.cpp -std=c++2a -Wall"
clang++ $1.cpp $2.cpp -std=c++2a -I=. -Wall -o $1l2a
if [  -e $1l2a ]; then
./$1l2a $3
fi
echo "\r"
echo "$ g++-7 $1.cpp $2.cpp -std=c++03  -Wall"
g++-7 $1.cpp  $2.cpp -std=c++03 -I=. -Wall -o $1g03
if [  -e $1g03 ]; then
./$1g03 $3
fi
echo "\r"
echo "$ g++-7 $1.cpp $2.cpp -std=c++17  -Wall" 
g++-7 $1.cpp $2.cpp -std=c++17 -I=. -Wall -o $1g17
if [  -e $1g17 ]; then
./$1g17 $3
fi
cpla3.sh
#!/bin/sh
echo "$ clang++ $1.cpp $2.cpp $3.cpp -std=c++03 -Wall"
clang++ $1.cpp $2.cpp $3.cpp -std=c++03 -I=. -Wall -o $1l03
if [  -e $1l03 ]; then
./$1l03 $4
fi
echo "$ clang++ $1.cpp $2.cpp $3.cpp -std=c++17 -Wall"
clang++ $1.cpp $2.cpp $3.cpp -std=c++17 -I=. -Wall -o $1l17
if [  -e $1l17 ]; then
./$1l17 $4
fi
echo "$ clang++ $1.cpp $2.cpp $3.cpp -std=c++2a -Wall"
clang++ $1.cpp $2.cpp $3.cpp -std=c++2a -I=. -Wall -o $1l2a
if [  -e $1l2a ]; then
./$1l2a $4
fi
echo "\r"
echo "$ g++-7 $1.cpp $2.cpp $3.cpp -std=c++03  -Wall"
g++-7 $1.cpp  $2.cpp $3.cpp -std=c++03 -I=. -Wall -o $1g03
if [  -e $1g03 ]; then
./$1g03 $4
fi
echo "\r"
echo "$ g++-7 $1.cpp $2.cpp $3.cpp -std=c++17  -Wall" 
g++-7 $1.cpp $2.cpp $3.cpp -std=c++17 -I=. -Wall -o $1g17
if [  -e $1g17 ]; then
./$1g17 $4
fi

参考資料

CERT CPP入門(1) Rule 01. Declarations and Initialization (DCL)
https://qiita.com/kaizen_nagoya/items/61b3c431756fe8e6af3e

Linux初心者のシェルスクリプト入門
https://qiita.com/lrf141/items/6c01d2f7afff79cd7286

ShellScriptでよく使う表現
https://qiita.com/rotocuir/items/986e8ee732730606622b

文書履歴

ver 0.10 初版 20180320
ver 0.11 第二引数渡し 20180321
ver 0.12 C++版追記 20180322
ver 0.13 gcc-7対応追記 20180407
ver 0.14 echo "\r"、prompt表記 echo "$"追記。20180407
ver 0.15 コンパイル対象ファイル2つ版、3つ版 20180407
ver 0.16 "-I."追記。カレントディレクトリのヘッダファイルを<>include可能に 20180407
ver 0.17 g++-7対応 20180408
ver 0.18 コンパイルエラー時に実行しない設定追記。
"if [ -e x ]; then" "x" "fi"
ver. 0.19 -std=c++17 版 20180415
ver. 0.20 -Wallをつけた。20180423
ver. 0.21 # -trigraph用にコンパイルオプションを記述できるようにした版(c++2011用)20180424
ver. 0.22 -std=c++03, -std=c++11, -std=c++17の3種類でコンパイルする記述追記 20180424
ver 0.23 N4606 Annex C(informative) Compatibility のため-std=c++14を追加した版を追記 20180503
ver 0.24 N4741 でclang++ -std=c++2aだけ使うスクリプトと、2aを含めた5種類のスクリプトのファイルが1つ、2つ、3つ版 20180507