macOS Sierraにpython3.6.3のソースコードを読むための環境を構築

pythonのソースコードを読むにあたりMacOSに環境を構築しました。その時のメモになります。Xcodeはインストールされていることが前提です。

#Pythonのダウンロード
適当なディレクトリを作成してそこにPythonの公式サイトからtgzファイルを持ってきます。

```shell-session
$ curl https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tgz -O
```
#Pythonのインストール

取得したtgzファイルを解凍して，生成されたディレクトリに移動します。

```shell-session
$ tar -xf Python-3.6.3.tgz
$ cd Python-3.6.3
```
`./configure --with-pydebug`を実行すると…コケました。

```shell-session
$ ./configure --with-pydebug

...

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.

checking for gcc... gcc
checking whether the C compiler works... no
configure: error: in `/Users/XXX/Python-3.6.3':
configure: error: C compiler cannot create executables
See `config.log' for more details
```

Xcodeのライセンスに合意する必要があるようです。表示されたコマンドをそのまま実行します。

```shell-session
sudo xcodebuild -license
```

条項が最後まで表示された後，`agree`と入力すると完了します。これで，`./configure`が通ります。

```shell-session
$ ./configure --with-pydebug
```
makeを実行します。

```shell-session
$ make
```

ビルドは成功しますが，下記のメッセージが表示されsqlite3，sslが利用できません。

```shell-session
Python build finished successfully!
The necessary bits to build these optional modules were not found:
_dbm                  _sqlite3              _ssl               
nis                   ossaudiodev           spwd               
zlib                                                           
To find the necessary bits, look in setup.py in detect_modules() for the module's name.

The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
atexit                pwd                   time  
$
```

[Python Developer's Guide](https://docs.python.org/devguide/setup.html#build-dependencies)次のコマンドを参考に次のコマンドを実行にしました。

```shell-session
$ xcode-select --install
$ brew install openssl xz
```

`make`で生成したファイルを削除するため，`make distclean`を実行して，再ビルドします。

```shell-session
$ make distclean
$ CPPFLAGS="-I$(brew --prefix openssl)/include" \
  LDFLAGS="-L$(brew --prefix openssl)/lib" \
  ./configure --with-pydebug
$ make

...

Python build finished successfully!
The necessary bits to build these optional modules were not found:
ossaudiodev           spwd                                     
To find the necessary bits, look in setup.py in detect_modules() for the module's name.

The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
atexit                pwd                   time        
$
```

…まだいくつか解消されないものが表示されますが，次に進みます。


#gdbの環境整備

gdbのバージョンが古いとエラーがデバッグができないことがあります。homebrewで最新版にしましょう。

```shell-session
$ brew uninstall gdb; brew install gdb
```

さきほど作成した`python`を`gdb`で実行してみます。

```shell-session
$ gdb python.exe
GNU gdb (GDB) 8.0.1

...

Reading symbols from python.exe...done.
(gdb) b builtin_dir
Breakpoint 1 at 0x1001d8414: file Python/bltinmodule.c, line 790.
(gdb) r
Starting program: /Users/XXXX/Python-3.6.3/python.exe 
Unable to find Mach task port for process-id 52003: (os/kern) failure (0x5).
 (please check gdb is codesigned - see taskgated(8))
(gdb) 

```

コード署名が必要なようなので，[こちら](https://qiita.com/takahashim/items/204ffa698afe09bd4e28)を参考に署名します。下記は実施後です。

```shell-session
$ gdb python.exe
GNU gdb (GDB) 8.0.1

...

Reading symbols from python.exe...done.
(gdb) b builtin_dir
Breakpoint 1 at 0x1001d8414: file Python/bltinmodule.c, line 790.
(gdb) r
Starting program: /Users/XXXX/Python-3.6.3/python.exe 
During startup program terminated with signal ?, Unknown signal.
```

上記のとおり，実際にデバックを実行してもエラーになってしまいます。このエラーを解消するため，下記のコマンドを実行します。

```shell-session
$ echo "set startup-with-shell off" >> ~/.gdbinit
```

これで，ブレークポイントを設定した場所で実行が停止できるようになりました。

```shell-session
$ gdb python.exe
GNU gdb (GDB) 8.0.1

...

Reading symbols from python.exe...done.
(gdb) b main
Breakpoint 1 at 0x10000158d: file ./Programs/python.c, line 28.
(gdb) r
Starting program: /Users/XXX/Python-3.6.3/python.exe 
[New Thread 0x1403 of process 739]
warning: unhandled dyld version (15)

Thread 2 hit Breakpoint 1, main (argc=1, argv=0x7fff5fbffa88) at ./Programs/python.c:28
28	    (void)_PyMem_SetupAllocators("malloc");
(gdb) 
```