0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jupyterのcell magicでcellのC/C++ソースをgcc/g++でコンパイルしよう

Posted at

概要

本格的な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++のコンパイル&実行

gcc_jupyter01.png

  • %%scriptは元々使えるCell Magicです
  • -xc, -xc++-xの後にコンパイルする言語
    • コンパイルがソースファイルではないのでファイルの拡張子がないため指定する
  • -はコンパイルするソースが標準入力から渡されることの指定
    • Cellのデータは標準入力渡しになる
  • その他は通常のコンパイルオプション
  • !はLine magicで!の後を実行する

コンパイルエラーがあると処理プロセスが異常終了したこととなるためPythonのTracebackが表示される
gcc_jupyter02.png

これを出さないようにしたい。


Tracebackを出さないためにscriptのオプション--no-raise-errorを追加する。
scriptのオプションを見るにはCellの先頭行に次ように?を追加して実行する。使い方が表示される。

%%script?

Tracebackが出てないことが確認できます。

gcc_jupyter03.png

Shellスクリプトの作成

gccやTracebackを出させないオプションなどが長くなるのでもっと簡単にするため、自分専用のShellスクリプトを用意します。下記のスクリプトはコンパイルエラーが無かったらバイナリを実行するスクリプトです。

mygcc
#!/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で変更してください。

gcc_jupyter04.png


エラーが無いソースの実行で、バイナリ名をcpptest1.outとしてコンパイル&実行。

gcc_jupyter05.png

スクリプトをCell magicとして登録

今度は%%scriptも書くのが面倒なので、上記で作成したmygccをCell magicとして登録します。そうすると、%%mygccとして書けます。

登録方法は、IPythonパッケージのあるソースを変更します。ファイルの更新権がない場合はたぶんできないので今までの方法で実行してください。

変更するソースは、%%script?で表示された最終行がそのファイル名です。
私の場合は以下のファイル名になります。

xxxxxx/site-packages/IPython/core/magics/script.py

script.pyに下記のようにmygccを追加します。だいたい、100行目ちょっとの所です。テキストエディタでbashperlで文字列検索して場所をみつけています。

script.py
   @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_jupyter06.png

終わりに

スクリプトは何個作っても良いのでオプション別に用意するといいと思います。
スクリプト名を分けることでオプションの記述が減ります。

例えば

  • 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を追加して出力するだけの単純な処理です。

source_edit.py
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 |をスクリプトに追加します。

mygcc
#!/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

gcc_jupyter07.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?