AWS SDK for C++のサンプルをVisual Studio Codeでデバッグする

C++でAWSのサービスを使う必要が出てきたのですが、幸いにも各言語ごとのサンプルコードが提供されているので、お勉強のために[以前作った開発環境](https://qiita.com/dbgso/items/6e2f317d6d13bdc387f8)でデバッグしてみました。



# はじめに

以前の記事と同様ですが

**注意** Docker上でgdbを使うためにセキュリティレベルを下げる設定を追加しています。外部に公開される環境では用いないようにしてください。


# 作業概要

[Visual Studio CodeのRemote ContainersでC++開発環境構築 - Qiita](https://qiita.com/dbgso/items/6e2f317d6d13bdc387f8) で作成したプロジェクトをベースに環境を作っていきます

変更するのは以下2点です。

1. `Dockerfile`にAWS SDKのビルド設定を追加する
1. `docker-compose.yml`のvolumesを変更する
    * マウントするパスの変更
    * AWSにアクセスするために`$HOME/.aws`をマウント


# プロジェクトをダウンロード
 
```bash
# ベースとなるプロジェクトをクローン
git clone https://github.com/dbgso/vscode-cpp-devcontainer.git vscode-remote-cpp-aws-sdkaws
# サンプルソースをダウンロード
git clone https://github.com/awsdocs/aws-doc-sdk-examples.git vscode-remote-cpp-aws-sdkaws/data/aws-doc-sdk-examples
# Visual Studio Codeで開く
code vscode-remote-cpp-aws-sdkaws
```

ここから、必要な設定を追加していきます

差分については https://github.com/dbgso/vscode-cpp-devcontainer/commit/c17e6ac33cc5512385ef3b1583d83c796bf10f9e をみてもらっても同じ内容です

## Dockerfile修正

変更内容は以下です。
AWS SDK for CPPの依存パッケージをインストールしてビルドしています。

```Dockerfile.diff
    apt-get install -y git build-essential cmake clang libssl-dev && \
    apt-get install -y cpputest libsqlite3-dev clang-format gdb

+# AWS dependency
+RUN apt-get install -y libcurl4-openssl-dev libssl-dev uuid-dev zlib1g-dev libpulse-dev
+
+RUN git clone https://github.com/aws/aws-sdk-cpp.git --depth 1 /tmp/aws-sdk-cpp
+RUN cd /tmp/aws-sdk-cpp && cmake -DBUILD_ONLY="s3" && make && make install
```

> 参考
> [Setting Up the AWS SDK for C++ - AWS SDK for C++](https://docs.aws.amazon.com/ja_jp/sdk-for-cpp/v1/developer-guide/setup.html)
> [DockerとMinioでAWS SDK for C++の開発環境を構築する - Qiita](https://qiita.com/kai_kou/items/d160948553504848d380)



## docker-compose.yml修正


現状の`devcontainer.json`の設定では`workingFolder`を`/data`としているので、`/data`にソースのルートを持ってくる必要があります。
ですので、`docker-compose.yml`のvolumesでマウントするディレクトリを変更します。
Dockerfileでも`-DBUILD_ONLY="s3"`としたので今回はs3のサンプルを試していきます。
マウントするパスは`/aws-doc-sdk-examples/cpp/example_code/s3/`となります。(あるいは`devcontainer.json`を変更して`"workspaceFolder": "/data/aws-doc-sdk-examples/cpp/example_code/s3/"`としても良いです。こっちの方が見通しが良いかな？)

```diff
version: '3.3'

services:
  cpp:
    build: .
    volumes:
-      - ../data:/data
+      - ../data/aws-doc-sdk-examples/cpp/example_code/s3/:/data
+      - $HOME/.aws/:/root/.aws
    working_dir: /data
    tty: true
    # to use gdb
    cap_add:
      - SYS_PTRACE
    security_opt:
      - seccomp:unconfined
```

# 起動

起動方法は前回の記事と変わりません。


![reopenincontainer](https://camo.qiitausercontent.com/f57c1f5989a79a862b46bc86d6a14115a37a21f9/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3333303531342f39633039333066302d393135652d656461322d383938302d3035623130313461353936642e706e67)

の`Reopen in Container`を選択するか、コマンドパレットから`Remote-Containers: Reopen Folder in Container`を実行します。


起動するとAWS SDKのビルドが始まりますが、結構長いのでしばらく待機します。(PCのスペックにもよりますが、5分〜15分程度？かかります)


## ビルド

コマンドパレットから`CMake: build`を実行します。
`No CMake kits are available`と聞かれたら`Do not use a kit`で良さそうです。(前回は選択してましたが、結局CMakeにお任せしていたので意味なかった？です)

こんな感じでログがつらつら流れれば成功です。

```
[cmake] The C compiler identification is GNU 7.4.0
[cmake] The CXX compiler identification is GNU 7.4.0
[cmake] Check for working C compiler: /usr/bin/cc
[cmake] Check for working C compiler: /usr/bin/cc -- works
[cmake] Detecting C compiler ABI info
[cmake] Detecting C compiler ABI info - done
[cmake] Detecting C compile features
[cmake] Detecting C compile features - done
[cmake] Check for working CXX compiler: /usr/bin/c++
[cmake] Check for working CXX compiler: /usr/bin/c++ -- works
[cmake] Detecting CXX compiler ABI info
[cmake] Detecting CXX compiler ABI info - done
[cmake] Detecting CXX compile features
[cmake] Detecting CXX compile features - done
[cmake] Found AWS SDK for C++, Version: 1.7.138, Install Root:/usr/local, Platform Prefix:, Platform Dependent Libraries: pthread;crypto;ssl;z;curl
[cmake] Components specified for AWSSDK: s3
[cmake] Try finding aws-cpp-sdk-core
[cmake] Found aws-cpp-sdk-core
[cmake] Try finding aws-cpp-sdk-s3
[cmake] Found aws-cpp-sdk-s3
[cmake] Configuring done
[cmake] Generating done
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /data/build --config Debug --target list_buckets -- -j 6
[build] Scanning dependencies of target list_buckets
[build] [ 50%] Building CXX object CMakeFiles/list_buckets.dir/list_buckets.cpp.o
[build] [100%] Linking CXX executable list_buckets
[build] [100%] Built target list_buckets
[build] Build finished with exit code 0
```

# 実行とブレークポイント


## バケット一覧取得

一番お手軽そうな`list_buckets.cpp`でバケットのリストを取得してみます。

まず、確認用に適当なバケットを作ってファイルを置いておきます(~~これもC++でやればいいんですが、記事にするのが面倒臭い~~)

```bash
$ aws s3 mb s3://cppbuckettest
make_bucket: cppbuckettest
$ echo hello > world.txt
$ aws s3 cp world.txt  s3://cppbuckettest
upload: ./world.txt to s3://cppbuckettest/world.txt           
$ aws s3 ls s3://cppbuckettest/
2019-07-04 13:06:47          6 world.txt
```


ブレークポイントを設定してステップ実行していくと、ちゃんと`cppbuckettest`の存在を確認できました。

![alt](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/a3d222de-fcb3-06b2-0378-b6c556c8fad3.png)

## オブジェクトの取得

せっかくファイルをアップロードしたので、バケットのファイル一覧を取得します。
サンプルのソースは`list_objects.cpp`です。

このファイルはコマンドライン引数にバケット名を渡して、そのバケットのファイル名一覧を取得しているみたいです。
ここで、ちょっとハマりました。
コマンドライン引数はどこに渡すの？って思ったんですが、普通に`launch.json`の設定に書けばよかったです。

`launch.json`を開いて、`C/C++: (gdb) Launch`を選択して、テンプレートを生成します。

以下のように、`program`に実行ファイル、`args`にコマンドライン引数を入れればOKです。

```diff
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
-           "program": "enter program name, for example ${workspaceFolder}/a.out",
+           "program": "${workspaceFolder}/build/list_objects",
-            "args": [],
+            "args": ["cppbuckettest"],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
```

`F5`キーで実行します

![alt](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/a6ce94aa-e60f-e1d0-50ac-6ad33cabaa1b.png)

ちゃんとブレークして、該当のバケット情報が取れています。
コンソールにも正しく表示されました

```
Objects in S3 bucket: cppbuckettest
* world.txt
```

    


# 備考


## .awsディレクトリのマウント漏れ

ちなみに、`.aws`ディレクトリをマウントし忘れると以下のように接続できなくて怒られるので注意しましょう

```
ListBuckets error:  - Unable to connect to endpoint
[1] + Done                       /usr/bin/gdb --interpreter=mi --tty=${DbgTerm} 0</tmp/Microsoft-MIEngine-In-2xmmhqio.v6u 1>/tmp/Microsoft-MIEngine-Out-l2adjy68.7nb
```

## CMake拡張機能を使ってのコマンドライン引数

本文では引数指定ができないと書いたのですが、すみません、できました。
ただ、使い勝手的には`launch.json`に書いてしまうのが良いと思うので、参考までに記録しておきます。

方法はVisual Studio Code側の設定に引数を設定してしまう方法です。

`Preferences: Open Workspace Settings`から`Workspace`ごとの設定を開き、以下のように`args`に設定します。


```setting.json
{    
    "cmake.debugConfig": {
        "args": [
            "bucket_name"
        ]
    }
}
```


あとは、通常通り`Debug`ボタンを押せば引数付きでデバッグできます

![alt](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330514/99942fd8-7d63-5ee6-1262-60499bf7e0c0.png)


ただ、おそらく設定は一つしかできないです。
Workspaceに設定するのでそれでも良さそうですが、使い勝手は悪そう。
ちなみにシステム側の設定にもできてしまいますが普通しませんよね。
おとなしく、`launch.json`が良いかなと思いました。お手軽実行の時はすごく楽で良いんですが

> 参考 [Passing command line arguments to a debug target · Issue #121 · vector-of-bool/vscode-cmake-tools](https://github.com/vector-of-bool/vscode-cmake-tools/issues/121)



# 参考


[Setting Up the AWS SDK for C++ - AWS SDK for C++](https://docs.aws.amazon.com/ja_jp/sdk-for-cpp/v1/developer-guide/setup.html)

[DockerとMinioでAWS SDK for C++の開発環境を構築する - Qiita](https://qiita.com/kai_kou/items/d160948553504848d380)

[Passing command line arguments to a debug target · Issue #121 · vector-of-bool/vscode-cmake-tools](https://github.com/vector-of-bool/vscode-cmake-tools/issues/121)