Edited at

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

More than 1 year has passed since last update.

コンパイル用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


整形台本


a.sh

#!/bin/bash

astyle -s2 -c -N < $1.cpp > $1s2.cpp
cat $1s2.cpp


参考資料

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

ver 0.30 整形台本追記 20180524