CMake入門

CMake入門

目次

1 概要

3 CMakeのインストール

  • Download https://cmake.org/download/ から、お使いのOS用のものをダウンロードしてインストール
    • Ubuntuなら以下のコマンドでインストール可能
sudo apt install cmake
  • この動画のシリーズではhttps://youtu.be/SWNKrXFkJpoで作成したDocker Imageを利用していきます。(CMakeやC++コンパイラ、その他必要なものはいっているため)
    • どのOSでもDockerを利用して同じ操作可能
    • ご自分のOSに直接CMakeをインストールして、Docker使わずやってもOK。(ほぼ同じ手順となります。)

3.1 説明動画


3.2 この章のまとめ

  • CMakeのインストール方法について説明
    • ダウンロードサイトから、ダウンロードしてインストール
  • どのOSでも共通で利用できる環境をDockerで解説してきます。
  • Dockerの環境の準備が面倒なら、必要なツールをインストールして直接やってもよい

4 C++ソースから実行ファイルの作成(シンプル)

4.1 以下の操作を行っている動画


4.2 C++ソースから実行ファイルの作成の手順

4.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

4.2.2 C++ソースの用意

  • Hello Worldと出力する例を作成
  • ファイル名はhelloworld.cpp
#include <iostream>

int main() {
  std::cout << "Hello world!" << std::endl;
  return 0;
}

4.2.3 CMakeLists.txtの用意

cmake_minimum_required(VERSION 3.4...3.18)
project(helloworld LANGUAGES CXX VERSION 1.0)
add_executable(helloworld helloworld.cpp)

4.2.4 コンパイル

  • ビルドするディレクトリに移動
mkdir build
cd build
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

4.2.5 動作確認

./helloworld

4.3 この章のまとめ

  • 簡単なC++のソースファイルから実行ファイルをコンパイルして動かしてみた

5 C++でライブラリの作成

5.1 以下の操作を行っている動画


5.2 C++でライブラリの作成の手順

5.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

5.2.2 C++ソースの用意

  • Hello Worldと出力する例を作成
  • ファイル名はmyadd.hpp
int myadd(const int &i, const int &j);
  • ファイル名はmyadd.cpp
    • 2つの引数をうけとり、足して返す関数
int myadd(const int &i, const int &j) {
  return i+j;
}

5.2.3 CMakeLists.txtの用意

cmake_minimum_required(VERSION 3.4...3.18)
project(myadd LANGUAGES CXX)
add_library(myadd myadd.cpp myadd.hpp)

5.2.4 コンパイル

  • ビルドするディレクトリに移動
mkdir build
cd build
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

5.2.5 コンパイル2 動的ライブラリ作成

  1. 方法1
    • あるいは cmake .. でも動的ライブラリを生成したい場合CMakeLists.txtのadd_libraryを以下のようにしても良い
      • 静的ライブラリの場合は SHARED を STATIC におきかえ
    add_library(myadd SHARED myadd.cpp myadd.hpp)
    
  2. 方法2-1
    cmake -DBUILD_SHARED_LIBS=TRUE ..
    
  3. 方法2-2
    • add_library(myadd myadd.cpp myadd.hpp) の行の前にsetで、環境変数をセット
    set(BUILD_SHARED_LIBS TRUE)
    add_library(myadd myadd.cpp myadd.hpp)
    

5.2.6 動作確認

  • 動作確認は省略します。このライブラリを利用する実行ファイルを作成してみてください。

5.3 この章のまとめ

  • 簡単なC++のソースファイルからライブラリをコンパイルして生成した。

6 C++でライブラリを作成し、それを利用した実行ファイルも作成

6.1 以下の操作を行っている動画


6.2 C++でライブラリの作成の手順

6.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

6.2.2 C++ソースの用意

  • 前の章のファイルに追加して、main.cppを追加
#include "myadd.hpp"
#include <iostream>

int main() {
  std::cout << myadd(1,2) << std::endl;
  return 0;
}

6.2.3 CMakeLists.txtの作成

cmake_minimum_required(VERSION 3.4...3.18)
project(myadd LANGUAGES CXX)
add_library(myadd SHARED myadd.cpp myadd.hpp)
add_executable(main main.cpp)
target_link_libraries(main myadd)

6.2.4 コンパイル

  • ビルドするディレクトリでコンパイル
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

6.2.5 動作確認

./main

6.3 この章のまとめ

  • 前章のライブラリをリンクして実行ファイルを作成するように、ファイルを追加したり、修正した

7 外部にあるライブラリをリンクして実行ファイルを作成1

7.1 以下の操作を行っている動画


7.2 外部にあるライブラリをリンクして実行ファイルを作成1 の手順

7.2.1 Dockerイメージの起動

  • ホストの/work/CMakeと、Dockerイメージ内の/home/user/Cディレクトリを共有するコマンドで起動
    • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK
docker run -it --rm -v /work/CMake:/home/user/C mypybind11

7.2.2 C++ソースの用意

  • 前の章のmain.cppはそのまま利用

7.2.3 CMakeLists.txtの作成

cmake_minimum_required(VERSION 3.4...3.18)
project(ex004 LANGUAGES CXX VERSION 1.0)
link_directories(../ex003/build/)
find_library(myadd NAMES myadd PATHS ../ex003/build REQUIRED)
message(${myadd})
add_executable(ex004 main.cpp)
include_directories(../ex003/)
target_link_libraries(ex004 PUBLIC myadd)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)

7.2.4 コンパイル

  • ビルドするディレクトリに移動
mkdir build
cd build
  • cmakeを実行
cmake ..
  • GNU Makeを実行しコンパイル
make

7.2.5 動作確認

./main

7.3 この章のまとめ

  • 外部の自作ライブラリを利用して、実行ファイルを作成するのをやってみた。(インクルードパスの設定と、外部ライブラリの指定)

8 外部にあるライブラリをリンクして実行ファイルを作成2

  • mライブラリを使う例
  • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK

8.1 以下の操作を行っている動画


8.2 外部にあるライブラリをリンクして実行ファイルを作成2 の手順

  • C++ソース example.cpp
#include <cmath>
#include <iostream>

int main() {
  std::cout << "sin(1)=" << sin(1) << std::endl;
  std::cout << "sin(0)=" << sin(0) << std::endl;
  std::cout << "cos(1)=" << cos(1) << std::endl;
  std::cout << "cos(0)=" << cos(0) << std::endl;
  return 0;
}
  • CMakeの設定ファイル CMakeLists.txt
cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-01 LANGUAGES CXX VERSION 1.0)
find_library(m NAMES m REQUIRED)
message(${m})
add_executable(ex006-01 example.cpp)
target_link_libraries(ex006 PUBLIC m)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
  • コンパイルは前章と同じ手順

8.3 この章のまとめ

  • mライブラリを使う例をやってみた

9 外部にあるライブラリをリンクして実行ファイルを作成2

  • mライブラリを使う例
  • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK

9.1 以下の操作を行っている動画


9.2 外部にあるライブラリをリンクして実行ファイルを作成2 の手順

  • C++ソース example.cpp
#include <cmath>
#include <iostream>

int main() {
  std::cout << "sin(1)=" << sin(1) << std::endl;
  std::cout << "sin(0)=" << sin(0) << std::endl;
  std::cout << "cos(1)=" << cos(1) << std::endl;
  std::cout << "cos(0)=" << cos(0) << std::endl;
  return 0;
}
  • CMakeの設定ファイル CMakeLists.txt
cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-01 LANGUAGES CXX VERSION 1.0)
find_library(m NAMES m REQUIRED)
message(${m})
add_executable(ex006-01 example.cpp)
target_link_libraries(ex006 PUBLIC m)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
  • コンパイルは前章と同じ手順

9.3 この章のまとめ

  • mライブラリを使う例をやってみた

10 外部にあるライブラリをリンクして実行ファイルを作成3

  • OpenCVライブラリを使う例
  • Dockerイメージはhttps://youtu.be/SWNKrXFkJpoで作成したものを利用してます。Docker使わず、直接ご利用のOSにCMakeやコンパイラ入れてやってもOK

10.1 以下の操作を行っている動画


10.2 外部にあるライブラリをリンクして実行ファイルを作成3 の手順

10.2.1 事前準備

  • OpenCVライブラリのインストール
    • 相当時間かかります。
sudo apt update
sudo apt install libopencv-dev 

10.2.2 C++ソース example.cpp 作成

  • 実行時のカレントディレクトリにある1.jpgを読み込んで、2.pngとして書き出すプログラム
#include <opencv2/opencv.hpp>
int main()
{
  cv::Mat image = cv::imread( "1.jpg");
  cv::imwrite("2.png",image);
  return 0;
}

10.2.3 CMakeの設定ファイル CMakeLists.txt 作成

cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-2 LANGUAGES CXX VERSION 1.0)
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
message(${OpenCV_INCLUDE_DIRS})
add_executable(ex006-2 example.cpp)
target_link_libraries( ex006-2 ${OpenCV_LIBS} )
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
  • コンパイルは前章と同じ手順

10.3 この章のまとめ

  • OpenCVライブラリを使う例をやってみた

11 外部にあるライブラリをリンクして実行ファイルを作成4

11.1 以下の操作を行っている動画


11.2 外部にあるライブラリをリンクして実行ファイルを作成4 の手順

11.2.1 装備されているリストを確認

cmake --help-module-list

11.2.2 C++ソース example.cpp 作成

11.2.3 CMakeの設定ファイル CMakeLists.txt 作成

cmake_minimum_required(VERSION 3.4...3.18)
project(ex006-3 LANGUAGES CXX VERSION 1.0)
find_package (Python COMPONENTS Development REQUIRED )
include_directories( ${Python_INCLUDE_DIRS} )
message(${Python_INCLUDE_DIRS})
add_executable(ex006-3 example.cpp)
target_link_libraries( ex006-3 ${Python_LIBRARIES} )
#set(CMAKE_VERBOSE_MAKEFILE TRUE)
#set(CMAKE_VERBOSE_MAKEFILE TRUE)

  • コンパイルは前章と同じ手順

11.3 この章のまとめ

  • 標準装備のライブラリを使う例をやってみた
    • ここではPython3

12 C++の指定(C++11,C++14,C++17,C++20,C++23等)

12.1 CやC++の指定方法

12.1.1 設定例

set(CMAKE_CXX_STANDARD 14) # C++14
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 満たせないならエラーに
set(CMAKE_CXX_EXTENSIONS OFF) # コンパイラの独自拡張をOFFに

12.1.2 注意点

  • project(XXX LANGUAGES CXX VERSION 0.01) という記述の前に上記の設定を行う必要あり。
    • 言語指定する前に設定しておく必要あり

12.1.3 備考

  • 設定ファイル内で指定しなくとも、cmake実行する時に環境変数を設定してもOK

12.2 この章のまとめ

  • C++14やC++17等が必要なときの設定方法

13 CやC++のコンパイラー指定

13.1 以下の操作を行っている動画


13.2 CやC++のコンパイラー指定

13.2.1 設定例1

  • PATHが通っているところから探してくれる
set(CMAKE_C_COMPILER    "clang")
set(CMAKE_CXX_COMPILER  "clang++")

13.2.2 設定例2

  • フルパスで指定
set(CMAKE_C_COMPILER    "/usr/bin/clang")
set(CMAKE_CXX_COMPILER  "/usr/bin/clang++")

13.2.3 注意点

  • project(XXX LANGUAGES CXX VERSION 0.01) という記述の前に上記の設定を行う必要あり。
    • 言語指定する前に設定しておく必要あり

13.2.4 備考

  • 設定ファイル内で指定しなくとも、cmake実行する時に環境変数を設定してもOK

13.3 この章のまとめ

  • clang++やclang等デフォルトで選ばれるコンパイラ以外を選択したい場合の設定方法

14 今後

  • 今後も文書追加していきます。

15 この文書のチェンジログ

  • 2021/05/17 初版
  • 2021/05/20 外部にあるライブラリをリンクして実行ファイルを作成1までの章かなり修正
  • 2021/05/21 C++の指定(C++11,C++14,C++17,C++20,C++23等) の章、 CやC++のコンパイラー指定 の章追加
  • 2021/05/24 外部にあるライブラリをリンクして実行ファイルを作成1の章追加
  • 2021/05/25 外部にあるライブラリをリンクして実行ファイルを作成2から4の章追加

著者: NM Max

Created: 2021-05-26 水 04:21

Validate

Mediapipeことはじめ

mediapipeことはじめ

1 概要

  • 瞳検出、Dlibよりも細かい顔ランドマーク検出、体のボーン検出など、相当良さげ

3 インストール(Python)

  • Pythonをインストールしてから、pip install mediapipeで、Pythonから使えるようになる(Linux,Windows,Mac等)

3.1 以下の操作を行っている動画


3.2 インストール(Python) する手順

  • Pythonがインストールされてて、pipあるいはpip3が使える環境で以下を実行
  • virtualenv で作成した方が良いかも。動画では virtualenv mediapipeしてから以下を行なった。
    • ipythonも追加でインストール
pip install mediapipe
or
pip3 install mediapipe

3.3 この章のまとめ

  • Python用のMediaPipeをインストール

4 顔のランドマーク(Python)検出

  • Pythonをインストールしてから、pip install mediapipeで、Pythonから使えるようになる(Linux,Windows,Mac等)

4.1 以下の操作を行っている動画


4.2 顔のランドマーク(Python)検出 する手順

  • MediaPipe Face Mesh https://google.github.io/mediapipe/solutions/face_mesh にあるサンプルソースを修正した
    • # For webcam input: までをコピペ
    • globを利用してカレントディレクトリにあるjpgファイルに対して処理
    • 元々は/tmpディレクトリに結果を書き出すが、ここでは、表示するように修正(オリジナルと、結果)
  • MediaPipe Face Mesh Colab https://mediapipe.page.link/face_mesh_py_colab もわかりやすい
  • 画像としては、パブリックドメインの”Yukichi_Fukuzawa_1891.png”File:Yukichi_Fukuzawa_1891.jpgを利用。他のファイルでもOK
  • ランドマークの描画の色がわかりにくいので、赤に変更するオプション追加
import cv2
import mediapipe as mp
import glob
mp_drawing = mp.solutions.drawing_utils
mp_face_mesh = mp.solutions.face_mesh

#file_list=["radu-florin-JyVcAIUAcPM-unsplash_small.jpg"]
file_list=glob.glob('*.jpg')

# For static images:
#drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1, color=(0, 0, 255))
with mp_face_mesh.FaceMesh(
    static_image_mode=True,
    max_num_faces=1,
    min_detection_confidence=0.5) as face_mesh:
  for idx, file in enumerate(file_list):
    image = cv2.imread(file)
    cv2.imshow('org', image)
    # Convert the BGR image to RGB before processing.
    results = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))

    # Print and draw face mesh landmarks on the image.
    if not results.multi_face_landmarks:
      continue
    annotated_image = image.copy()
    for face_landmarks in results.multi_face_landmarks:
      print('face_landmarks:', face_landmarks)
      mp_drawing.draw_landmarks(
	  image=annotated_image,
	  landmark_list=face_landmarks,
	  connections=mp_face_mesh.FACE_CONNECTIONS,
	  landmark_drawing_spec=drawing_spec,
	  connection_drawing_spec=drawing_spec)
    cv2.imshow('result', annotated_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    #cv2.imwrite('/tmp/annotated_image' + str(idx) + '.png', annotated_image)

4.3 この章のまとめ

  • Python用のMediaPipeで顔のランドマーク(Python)検出を行った。

5 今後

  • 今後も文書追加していきます。

6 この文書のチェンジログ

  • 2021/02/19 初版
  • 2021/05/17 長期放置の後、修正、追加

著者: NM Max

Created: 2021-05-20 木 05:49

Validate

pybind11ことはじめ

pybind11ことはじめ

目次

1 概要

  • C++11をPythonで利用しやすくするツールの一種
    • ヘッダーファイルのみで構成されている
    • DlibのPythonとの連携で使われていて調べた

2 関連文書

3 環境構築(Dockerを利用して)

  • 色々なOS(Windows,Mac,Linux)で、同じ操作で出来るように、Dockerを利用して環境を作る
  • Docker無しで、必要なツールをインストールして直接やってもOK(その場合この章はスキップ)
    • 必要なツール
      • C++のコンパイラ
      • CMake
      • GNU Make
      • Python とヘッダーファイル、ライブラリファイル
      • Python のライブラリ
        • pip
        • pybind11
    • あった方が良いもの
      • git
      • Python のライブラリ
        • ipython

3.1 以下の操作を行っている動画


3.2 環境構築(Dockerを利用して)の手順

3.2.1 事前準備

  • OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
  • まずDockerをインストールしてください。
    • 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
  • Docker等でUbuntuの環境を用意
    • Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
  • 以下のコマンドで、共有用のディレクトリ作成し、user idを1000にしておく
sudo mkdir -p /work/pybind11
sudo chown 1000.1000 /work/pybind11

3.2.2 DockerのUbuntu20.04を利用して毎回必要なパッケージを入れる場合

  • ubuntu20.04を起動する
    • Docker内の/homeを/work/pybind11と共有
docker run -it --rm -v /work/pybind11:/home/ ubuntu:20.04
  1. Docker内で、必要なパッケージのインストール
    apt update
    apt upgrade
    apt -y install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 nkf less diffutils patch sudo zlib1g-dev unzip locales 
    locale-gen ja_JP.UTF-8
    
    • pybind11パッケージのインストール
    pip3 install pybind11
    

3.2.3 pybind11を利用するのに必要なパッケージを入れたDockerイメージを作成する場合

  1. Dockerfileの準備
    • 以下の内容でDockerfileを作成
    FROM ubuntu:20.04
    MAINTAINER NM Max
    ENV user_n=user
    ENV user_id=1000
    #ENV DEBIAN_FRONTEND=noninteractive
    RUN apt -y update \
        && apt -y upgrade \
        && echo "6\n79\n" | apt -y install tzdata
    RUN apt -y install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 nkf less diffutils patch sudo zlib1g-dev unzip locales \
        && locale-gen ja_JP.UTF-8 \
        && pip3 install pybind11
    ENV LC_ALL ja_JP.UTF-8
    ENV LANG ja_JP.UTF-8
    ENV LANGUAGE LANGUAGE=ja_JP:ja
    RUN echo 'LANG="ja_JP.UTF-8"' >> /etc/default/locale
    RUN echo "${user_n} ALL=NOPASSWD: ALL" >> /etc/sudoers
    WORKDIR /work
    RUN echo "\n\n\n\n\n\n\n" | adduser --uid ${user_id} --disabled-password ${user_n}
    RUN echo "user ALL=NOPASSWD: ALL" >> /etc/sudoers && chown user.user /work
    RUN mkdir -p /home/${user_n}/C && chown  ${user_n}.${user_n} /home/${user_n}/C
    ENTRYPOINT sudo su - ${user_n}
    
    • 以下のコマンドでイメージ作成
    docker build -t mypybind11 .
    
    • 作成したDockerイメージの起動は以下のコマンドで
    docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
    

3.3 この章のまとめ

  • どのOSでも共通で利用できる環境をDockerで作成
  • Dockerの環境の準備が面倒なら、必要なツールをインストールして直接やってもよい

4 本家の文書のFirst stepsをやってみる

4.1 以下の操作を行っている動画


4.2 本家の文書のFirst stepsをやる手順

4.2.1 事前準備

  • OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
  • まずDockerをインストールしてください。
    • 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
  • Docker等でUbuntuの環境を用意
    • Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
  1. 前の章で作成したmypybind11イメージを利用する場合
    • 前の章で作成した専用Dockerイメージmypybind11を起動
      • /work/pybind11 を Docker内の/homeと共通にしてます。
    docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
    
    • 起動したDocker環境内で以下を実行
      • ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
    cd /home/user/C
    mkdir test001
    cd test001/
    pwd
    
    • /home/user/C/test001 と表示され、現在の作業しているディレクトリを確認できます。
  2. 前の章で作成したmypybind11イメージを利用せずにUbuntu20.04を利用する場合
    • この場合、必要なものが入ってないので、Dockerイメージ起動あとに、必要なものを入れる必要があります。
    docker run -it --rm -v /work/pybind11:/home Ubuntu20.04
    
    • 以下を実行して必要なパッケージを入れる
    apt update
    apt upgrade
    apt install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3
    pip3 install pybind11
    
    • 起動したDocker環境内で以下を実行
      • ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
    cd /home/
    mkdir test001
    cd test001/
    pwd
    
    • /home/test001 と表示され、現在の作業しているディレクトリを確認できます。

4.2.2 example.cppの準備

4.2.3 コンパイル

c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)

4.2.4 動作確認

  • 対話環境で動作確認した方がやりやすいので、IPythonを起動する
ipython3
  • 作成したモジュールの読み込み
import example                                                                                                                                
  • 1+2をやってみる
example.add(1,2)                                                                                                                              
  • 1+2で3が表示されます
  • 次に5+6をやってみる。
example.add(5,6)   
  • 5+6で11が表示されます

4.3 この章のまとめ

  • 本家文書のFirst stepsをやってみた
  • 使い方の基本の確認
  • C++で作成した関数をPythonで利用する手順の理解

5 CMakeで前章の内容をやってみる

5.1 以下の操作を行っている動画


5.2 cmakeで前章の内容をやってみる手順

5.2.1 事前準備

  • 必要なソフトを入れる
  • 前の章のexample.cppを入れておく
  • example.cppのあるディレクトリに移動
  1. 以下のコマンドでpybind11の最新バージョンをダウンロードして利用しても良い
    git clone https://github.com/pybind/pybind11
    
    • 以下のコマンドでバックアップ取っておいても良いかも
    tar cvzf pybind11_`date +%Y%m%d_%H%M`.tgz pybind11/
    

5.2.2 CMakeLists.txt の準備

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

5.2.3 コンパイル

mkdir build
cd build
cmake ..
make 
  • 前の章と同じ手順で動作確認すべき

5.3 この章のまとめ

  • 前章の内容をcmakeを利用してやってみた
  • コンパイルがちょい楽に

6 classを利用その1

6.1 以下の操作を行っている動画


6.2 classを利用その1の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

6.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

6.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test002
cd test002/
pwd

6.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

6.2.4 example.cppの作成

  • 前の章で利用したものに簡単なクラスTest01を追加
  • Class Test01をPython側で利用出来るようにコード追加
    • def_readwrite でpublicのメンバ変数を参照してPythonから使えるようにした
    • コンストラクタと、helloメンバ関数を参照してPythonから使えるようにした
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

class Test01 {
        public:
                Test01(const std::string &s) {
                        name=s;
                }
                std::string name;
                std::string hello() {
                        return "Hello "+name+"!";
                }
};

// https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
// https://pybind11.readthedocs.io/en/stable/classes.html#binding-lambda-functions
PYBIND11_MODULE(example, m) {
        m.doc() = "pybind11 example plugin"; // optional module docstring

        m.def("add", &add, "A function which adds two numbers");
        py::class_<Test01>(m, "Test01")
                .def(py::init<const std::string &>())
                .def_readwrite("name", &Test01::name)
                .def("hello", &Test01::hello);
}

6.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

6.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

6.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
m=example.Test01("Tom")
m.name
m.hello()
  • 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
  • 内部の情報とかは現状見れない。次の章でここらの表現をカスタマイズします。
  • 次の章で、ダイナミックに属性を追加出来るようにするので、現在出来ないことを確認
m.age=32                                                                                                                                      
  • AttributeError: ‘example.Test01’ object has no attribute ‘age’ が表示される

6.3 この章のまとめ

  • classをやってみた。

7 classを利用その2

7.1 以下の操作を行っている動画


7.2 classを利用その2の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

7.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

7.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test003
cd test003/
pwd

7.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

7.2.4 example.cppの作成

  • 前の章で利用したものに多少修正
    • Class Test01のpybind11用記述部分に2箇所追加
      • py::dynamic_attr()追加 これにより 動的に属性追加可能に。 dict でそれらの情報出てくる。
        • .def(“repr“, …. 部分追加 これにより、クラスオブジェクトの表示をカスタマイズ
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

class Test01 {
        public:
                Test01(const std::string &s) {
                        name=s;
                }
                std::string name;
                std::string hello() {
                        return "Hello "+name+"!";
                }
};

PYBIND11_MODULE(example, m) {
        m.doc() = "pybind11 example plugin"; // optional module docstring

        m.def("add", &add, "A function which adds two numbers");
        py::class_<Test01>(m, "Test01", py::dynamic_attr())
                .def(py::init<const std::string &>())
                .def_readwrite("name", &Test01::name)
                .def("hello", &Test01::hello)
                .def("__repr__",
                        [](const Test01 &a) {
                            return "<example.Test01 named '" + a.name + "'>";
                        }
                );
}

7.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

7.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

7.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
m=example.Test01("Tom")
m.name
m.hello()
  • 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
  • 表示がカスタマイズされて、nameの情報が表示されるようになった
  • 動的に属性を追加出来るようになっているので、試す。
m.age=32                                                                                                                                      
m.age  
print(m.__dict__)
  • 内部情報が表示されるようになった。

7.3 さらなる使い方

7.4 この章のまとめ

  • 前章のClassに動的に属性を追加出来るようにした。
  • 前章のClassを文字列化した時の表現のカスタマイズを行った。

8 コンテナを利用(std::vector) 1

8.1 以下の操作を行っている動画


8.2 コンテナを利用(std::vector) 1 の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

8.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

8.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test004
cd test004/
pwd

8.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

8.2.4 example.cppの作成

  • pybind11/stl.h をインクルード
  • C++ で2つの関数を定義
    • range関数,最初、最後、差を与えると、等差数列をかえす関数
      • 無限ループ回避の処理をいれたら、ちょい不細工に
    • concatv 2つの整数(int)の数列を結合してかえす関数
  • Pythonに渡す関数の記述
    • 2つの関数の記述
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
namespace py = pybind11;

std::vector<int> range(int st, int end, int diff) {
  std::vector<int> ans;
  bool flag=(end-st)*diff>=0;
  if(flag && diff!=0) {
    if(end>=st) {
      for(int i=st;i<=end;i+=diff) {
        ans.push_back(i);
      }
    } else {
      for(int i=st;i>=end;i+=diff) {
        ans.push_back(i);
      }
    }
  } else {
    ans.push_back(st);
  }
  return ans;
}       

std::vector<int> concatv(const std::vector<int> &a, const std::vector<int> &b) {
  std::vector<int> ans;
  for(int i=0;i<a.size();++i) {
    ans.push_back(a[i]);
  }
  for(int i=0;i<b.size();++i) {
    ans.push_back(b[i]);
  }
  return ans;
}       

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  m.def("range", &range, "A function which make a arithmetic progression");
  m.def("concatv", &concatv, "A function which concatenate two int vector");
}

8.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

8.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

8.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
example.range(1,10,1)
example.range(1,10,2)
example.range(10,1,-1)
example.range(1,10,-1)
example.range(1,10,0)
example.concatv([5,6],[1,2,3])
example.concatv([1,2,3],[4,5])

8.3 この章のまとめ

  • std::vectorを使ったC++関数をPython側から使えるようにしてみた。

9 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例)

9.1 以下の操作を行っている動画


9.2 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の手順

9.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

9.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test005
cd test005/
pwd

9.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

9.2.4 example.cppの作成

 - このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる  - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき

  • 意図する動作にする手順は次の章で
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */


PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

9.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

9.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

9.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
v=[1,2,3]
example.append_1(v)
v
  • [1,2,3,1]ではなく[1,2,3]がかえってくる
  • クラスの方もやってみる
m = example.MyClass()
m.contents = [5, 6]
m.contents
m.contents.append(7)
m.contents
  • これも[5,6,7]ではなく[5,6]がかえってくる

9.3 この章のまとめ

10 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)

10.1 以下の操作を行っている動画


10.2 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)手順

  • 手順は前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

10.2.1 example.cppの作成

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <string>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */

PYBIND11_MAKE_OPAQUE(std::vector<int>);

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  py::class_<std::vector<int>>(m, "IntVector")
    .def(py::init<>())
    .def("clear", &std::vector<int>::clear)
    .def("pop_back", &std::vector<int>::pop_back)
    .def("push_back", (void (std::vector<int>::*)(const int &)) &std::vector<int>::push_back)
    .def("__len__", [](const std::vector<int> &v) { return v.size(); })
    .def("__iter__", [](std::vector<int> &v) {
       return py::make_iterator(v.begin(), v.end());
    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */

  m.def("print_opaque_list", [](const std::vector<int> &l) {
        std::string ret = "Opaque list: [";
        bool first = true;
        for (auto entry : l) {
            if (!first)
                ret += ", ";
            ret += std::to_string(entry);
            first = false;
        }
        return ret + "]";
    });


  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

10.2.2 動作確認

import example
m=example.MyClass()
example.print_opaque_list(m.contents)
m.contents.push_back(1)
m.contents.push_back(2)
example.print_opaque_list(m.contents)
example.append_1(m.contents)
example.print_opaque_list(m.contents)
example.append_1(m.contents)
example.print_opaque_list(m.contents)

10.3 この章のまとめ

11 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う)

11.1 以下の操作を行っている動画


11.2 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) 手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

11.2.1 example.cppの作成

 - このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる  - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき

  • 意図する動作にする手順は次の章で
  • ../pybind11/tests/test_opaque_types.cpp を参考に
    • push_backを追加(std::vector<int>用に修正)
    • print_opaque_list(std::vector<int>用に修正)
#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>
#include <vector>
#include <string>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */

PYBIND11_MAKE_OPAQUE(std::vector<int>);

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  py::bind_vector<std::vector<int>>(m, "VectorInt");

  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

11.2.2 動作確認

import example
m=example.MyClass()
m.contents
m.contents=example.VectorInt([1,2,3])
example.append_1(m.contents)
m.contents
m.contents.append(5)
m.contents

11.3 この章のまとめ

12 引数に名前をつける

12.1 以下の操作を行っている動画


12.2 引数に名前をつける手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

12.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

 // m.def("add", &add, "A function which adds two numbers"); // org
    m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j"));
}

12.2.2 動作確認

import example
example.add(i=1,j=2)

12.3 この章のまとめ

13 引数にデフォルト値を設定

13.1 以下の操作を行っている動画


13.2 引数にデフォルト値を設定する手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

13.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

 // m.def("add", &add, "A function which adds two numbers"); // org
 // m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j")); // 前の章
    m.def("add", &add, "A function which adds two numbers", py::arg("i")=1, py::arg("j")=2);
}

13.2.2 動作確認

import example
example.add(i=2)
example.add(j=3)
example.add()

13.3 この章のまとめ

14 変数のエクスポート

14.1 以下の操作を行っている動画


14.2 変数のエクスポート 手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

14.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

PYBIND11_MODULE(example, m) {
    m.attr("the_answer") = 42;
    py::object world = py::cast("World");
    m.attr("what") = world;
}

14.2.2 動作確認

import example
example.the_answer
example.the_answer=53
example.the_answer
example.what
example.what="hoho"
example.what

14.3 この章のまとめ

15 オーバーロードされたメソッド

15.1 以下の操作を行っている動画


15.2 オーバーロードされたメソッドをPythonで利用する手順

  • C++14以前の方法と、C++14以降とでやり方2つある
  • C++14以降の方が記述が楽なので、こっちだけ動画で説明します。(もう一つの方法は Overloaded methods https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methodsをご覧ください)
  • pybind11では自動で、それらのメソッドを自動で選択してくれない、なので、ひとつひとつ引数を記述して記述していく
  • Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。

15.2.1 C++ソースファイルの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

struct Widget {
  int foo(int x, float y) {
    return x+y;
  }
  int foo(int x, float y) const {
    return x-y;
  }
};

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring
    py::class_<Widget>(m, "Widget")
       .def(py::init<>())
       .def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
       .def("foo_const",   py::overload_cast<int, float>(&Widget::foo, py::const_));
}

15.2.2 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)

set(CMAKE_CXX_STANDARD 14)          # C++14以上に設定する
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 設定のC++のバージョン条件を満たせないならエラーにする
set(CMAKE_CXX_EXTENSIONS OFF)       # 互換性を高める

project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

15.2.3 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

15.2.4 コンパイル

  • 以前の章と同じコマンド
mkdir build
cd build
cmake ..
make 

15.2.5 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
w=example.Widget()
w.foo_mutable(1,2)
w.foo_const(1,2)

15.3 この章のまとめ

  • オーバーロードされたメソッドの取扱方法の1つを行なった。

16 モジュール名に注意

  • CMakeLists.txt内のモジュール名とc++ソースのモジュール名が異ると、コンパイルは可能なのですが、モジュール読み込み時にエラーが発生
  • Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。

16.1 以下の操作を行っている動画


16.2 モジュール名に注意 の確認手順

  • 前のソースのCMakeLists.txtの pybind11_add_module(example example.cpp) を pybind11_add_module(widget example.cpp) とか、別名にしてみる
  • コンパイルしなおして、モジュール読み込むと以下のエラーが発生
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-64ca027457b3> in <module>
----> 1 import widget

ImportError: dynamic module does not define module export function (PyInit_widget)
  • ということで、 CMakeLists.txt内のモジュール名と、C++ソースのモジュール名同じにする必要があります。(こないだこれでハマり、時間ロスしました)

16.3 この章のまとめ

  • CMakeLists.txt のモジュール名と、C++ソースで記述したモジュール名は同じにしましょう。そうしないとエラー発生。

17 今後

  • 今後も文書追加していきます。

18 この文書のチェンジログ

  • 2021/05/08 初版
  • 2021/05/10 classを利用その1 の章, classを利用その2 の章追加
  • 2021/05/10 Dockerイメージの起動のコマンドに誤りがあったので修正
  • 2021/05/11 コンテナを利用(std::vector) 1 の章追加
  • 2021/05/12 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の章、コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う) の章、 * コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) の章追加
  • 2021/05/13 引数に名前をつける の章、 引数にデフォルト値を設定 の章、 変数のエクスポート の章追加
  • 2021/05/21 オーバーロードされたメソッド の章追加, モジュール名に注意 の章追加
  • 2021/05/24 BlogへのアップロードをMarkDownに変換して登録するように変更

著者: NM Max

Created: 2021-05-24 月 23:42

Validate