概要
本格的なC/C++プログラミングはVscodeなどIDEを利用して作ることになると思います。しかし、C/C++の勉強やちょっとしたコードの実験などはJupyter notebookが使えると便利です。
Jupyter notebookにはMarkdownが書けるのでちょっとしたコードの勉強や実験などのコメントとコードの両方を書けて、さらに複数のプログラムが同一のnotebook上で見られる利点があると思う。
個人的には別の記事に書いてある通りCERN ROOT Jupyter notebookがおすすめだが、インストールや使い方を覚えるのが面倒だったりする人には簡単にcell magicでコンパイルできれば良いのではないかと思います。また、CERN ROOTはC++17なので、他にC++11, C++23とか試すには不向きです。
- CERN ROOT Jupyer notebook
実行環境
> sw_vers
ProductName: macOS
ProductVersion: 15.3.2
BuildVersion: 24D81
> gcc --version
Apple clang version 16.0.0 (clang-1600.0.26.6)
Target: arm64-apple-darwin24.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
> python --version
Python 3.13.2
Jupyterでgcc/g++のコンパイル&実行
-
%%script
は元々使えるCell Magicです -
-xc
,-xc++
は-x
の後にコンパイルする言語- コンパイルがソースファイルではないのでファイルの拡張子がないため指定する
-
-
はコンパイルするソースが標準入力から渡されることの指定- Cellのデータは標準入力渡しになる
- その他は通常のコンパイルオプション
-
!
はLine magicで!
の後を実行する
コンパイルエラーがあると処理プロセスが異常終了したこととなるためPythonのTracebackが表示される
これを出さないようにしたい。
Tracebackを出さないためにscriptのオプション--no-raise-error
を追加する。
scriptのオプションを見るにはCellの先頭行に次ように?
を追加して実行する。使い方が表示される。
%%script?
Tracebackが出てないことが確認できます。
Shellスクリプトの作成
gcc
やTracebackを出させないオプションなどが長くなるのでもっと簡単にするため、自分専用のShellスクリプトを用意します。下記のスクリプトはコンパイルエラーが無かったらバイナリを実行するスクリプトです。
#!/bin/bash
if [ $# -eq 0 ]; then
NAME="a.out"
else
NAME="$1"
shift
fi
g++ -xc++ - -std=c++11 -o ${NAME} "$@" && ./${NAME}
if [ $? -ne 0 ]; then
echo
fi
スクリプトの引数の1番目をバイナリ名として、残りをコンパイルオプションとします。また、引数がひとつも無いときはバイナリ名をa.out
とする。そして、コンパイルエラーないときバイナリを実行する。 コンパイルエラーがないと&&
以降が実行されます。コンパイルエラーがあるとechoが実行されて、スクリプトが正常終了するのでTracebackが表示されません。
mygcc
が実行可能なようにchmod u+x mygcc
で変更してください。
エラーが無いソースの実行で、バイナリ名をcpptest1.out
としてコンパイル&実行。
スクリプトをCell magicとして登録
今度は%%script
も書くのが面倒なので、上記で作成したmygcc
をCell magicとして登録します。そうすると、%%mygcc
として書けます。
登録方法は、IPythonパッケージのあるソースを変更します。ファイルの更新権がない場合はたぶんできないので今までの方法で実行してください。
変更するソースは、%%script?
で表示された最終行がそのファイル名です。
私の場合は以下のファイル名になります。
xxxxxx/site-packages/IPython/core/magics/script.py
script.py
に下記のようにmygcc
を追加します。だいたい、100行目ちょっとの所です。テキストエディタでbash
かperl
で文字列検索して場所をみつけています。
@default('script_magics')
def _script_magics_default(self):
"""default to a common list of programs"""
defaults = [
'sh',
'bash',
'perl',
'ruby',
'python',
'python2',
'python3',
'pypy',
'mygcc', # 追加
]
restart kernel
でカーネルを再起動をして変更が反映されるようにしてください。
終わりに
スクリプトは何個作っても良いのでオプション別に用意するといいと思います。
スクリプト名を分けることでオプションの記述が減ります。
例えば
- gcc汎用 -- mygcc
- gccでxxx Library用 -- myxxxで-I -L -lなどのオプションを記述しておく
- g++汎用 -- mygpp
- g++でc++11用 -- myg11
- g++でc++17用 -- myg17
- ...
Appendix
main
関数内でのコードしか書く必要がなく、main
内のコードだけ書きたい時も対応した参考例
次のPythonスクリプトを用意します。
int main
がcellデータに含まれていたらそのまま出力して、含まれていなければヘッダーファイルのincludeとmainを追加して出力するだけの単純な処理です。
import sys
def print_main(src):
print("""
#include <iostream>
int main() {
""")
print(src)
print("""
return 0;
}
""")
cell_src = sys.stdin.read()
if "int main" in cell_src:
print(cell_src)
else:
print_main(cell_src)
g++
の前にpython source_edit.py |
をスクリプトに追加します。
#!/bin/bash
if [ $# -eq 0 ]; then
NAME="a.out"
else
NAME="$1"
shift
fi
python source_edit.py | g++ -xc++ - -std=c++11 -o ${NAME} "$@" && ./${NAME}
if [ $? -ne 0 ]; then
echo
fi