C++の標準描画ライブラリに入るかもしれないCairoのサンプルをwindows向けにビルドしてみた
cairoとC++
本の虫: Herb SutterがCairoのMLにC++標準規格にCairoを入れられないか打診中
環境
- windows
- msys2
依存関係
$ pacman -S mingw-w64-x86_64-zlib $ pacman -S mingw-w64-x86_64-libpng $ pacman -S mingw-w64-x86_64-pixman $ pacman -S mingw-w64-x86_64-cairo
サンプル
ビルド
$ x86_64-w64-mingw32-g++ -I/mingw64/include main.cpp -L /mingw64/lib -lcairo -lgdi32
上記ソースとはパスが違うのでcairo-win32.h
をcairo/cairo-win32.h
としました。
基本クラスの継承を考えたデストラクタの属性設定
概要
この記事は間違った情報が多分に含まれるため
と
の翻訳記事に書き換える予定です。
以下元の記事。
実行時の型とポインタの型が違う場合、ただnewするだけでは実行時の型情報がロストするので、ちゃんとtype erasure
するかvirtualを付けましょう。
型情報がロストして困る例
#include <iostream> struct Foo{ ~Foo(){ std::cout << "Foo" << std::endl; } }; struct Bar: public Foo{ ~Bar(){ std::cout << "Bar" << std::endl; } }; int main(){ Foo *bar = new Bar(); delete bar; }
このコードではBarのデストラクタが実行されません。何故ならBarの型情報をどこにも保持していないからです。
virtualで解決する
struct Foo{ virtual ~Foo(){ std::cout << "Foo" << std::endl; } };
そこでデストラクタにvirtualを付けてやるとBarの型情報が(正確にはオーバーライドされた関数へのポインタ)が保持されるのでBarのデストラクタが実行されるようになります。
type erasureで解決する
int main(){ std::shared_ptr<Foo> bar(new Bar); }
std::shared_ptr
はtype erasure
というテクニックを使い型を内部で保持します。なのでBarのデストラクタにvirtualが付いていなくてもBarのデストラクタが実行されます。
どっちを使うべきか
Foo
がインターフェイスの場合継承される意図を明確にする為にvirtualを付けるのが良いと思います。反対にFoo
がただの一般クラスで同じ機能を流用したくて継承する場合はvirtualを付ける事を推奨しません。こういう場合は使いたい機能をインターフェイスに分離すべきです。
インターフェイスが何らかの事情で用意できない場合ですらstd::shared_ptr
で解放するのは意図が明白にならないのでオススメしません。継承先解放用のクラスを作成するのが本来なら良いのですが、このような複雑なテンプレートはしっかりとテストできる環境でのみ作成すべきです。なので、妥協案として継承先解放用のクラスをshared_ptrのエイリアスとして定義すると良いと思います。
余談
std::unique_ptr
は型情報を内部で保存していません。なので、継承先のデストラクタは実行されません。
シングルトンを使うのはやめよう
概要
この記事はC++の作者Bjarne Stroustrup
等によって書かれたコーディングガイドラインのAvoid singletons
の箇所の翻訳です。
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Ri-singleton
シングルトンを使うのはやめよう
理由
シングルトンは基本的に変装したグローバルオブジェクトに過ぎないため。
例
class Singleton { // シングルトンオブジェクトが確実に1つだけ作られて // プロパティの初期化が行われるようにする };
シングルトンという発想には多くの亜種がある。 それが問題の1つである。
メモ
あなたがグローバルオブジェクトを変更したくない場合、const
またはconstexpr
を宣言する。
例外
最初の使用での初期化を行うための純粋なシングルトン(設計を考えなくて良いような)の場合は使用できる。
X& myX() { static X my_x {3}; return my_x; }
これは初期化順を制御する最も効果的な解決策の1つだ。 マルチスレッド環境において静的オブジェクトはレースコンディションを引き起こさない。(うっかりそのコンストラクタ内から共有オブジェクトにアクセスしない限り)
もし、あなたが他の大勢のようにシングルトンをオブジェクトを1つだけ作成するためのクラスと定義するのなら、myX
のような関数はシングルトンではない。そして、この便利なテクニックはシングルトンを無くすルールの例外ではない。
実施
一般化することは非常に難しい。
singleton
を含む名前を持つクラスを探す。- 作成された単一オブジェクトを探す。(オブジェクトを数えたりコンストラクタを調査する)
- クラスXの持つpublic static関数が内部に静的なクラスXを持ち、それのポインタや参照を返している場合、それを禁止する。
DirectX12をビルド可能なプロジェクトを作る
前回
ようやくWindows10にしたのでDX12プログラミングを始めてみた - ぷろみん
ビルド
New Project -> Win32 Project -> Empty Project
新しく生成されたフォルダに前回ビルドに成功したサンプルの.cppと.hをコピーしてきます。
Solution Explorerのファイルが並んでいるアイコン(Show All File)をクリックし、先ほどコピーしたファイルを出現させます。
そして、全選択してから右クリックInclude In Projectします。
1からソースを書く場合は省略できますが、d3dx12.h
はSDKに含まれていないので注意が必要です。
How to: Use the Windows 10 SDK in a Windows Desktop Application
を参考にRetarget SDK Version
すると前回設定した項目が入力可能になります。
プロジェクトのプロパティを開き利用したいバージョンを指定しましょう。
そして、プロジェクトのプロパティの右上にあるConfiguration ManagerからActive solution platformの箇所をx64に変更します。
最後にLinker -> Input -> Additional Dependenciesにd3d12.lib
とdxgi.lib
を加えるとビルドできます。
ようやくWindows10にしたのでDX12プログラミングを始めてみた
概要
Windows10にしたらまず最初にすべき事といえば・・・
そう、DirectX12プログラミングですよね。
今回はその導入をやってみたのでメモしておきます。
Visual Studioのアップグレード
始めから入ってない人もここで入れるので一緒です。
Direct3D12 開発環境構築 -プレビュー版- :: ☆PROJECT ASURA☆
ここの手順に従ってインストーラーをDLして実行し、アップグレードが終わった後に変更からWindows SDK10を導入します。
アップグレードの場合は(もしくは最新のビルドでは不要)Windows 10 Developer Preview Toolsはインストール済みでした。
動作確認
Git for WindowsやCygwin、MinGW等でgitを入れます。
$ git clone https://github.com/Microsoft/DirectX-Graphics-Samples $ cd DirectX-Graphics-Samples/Samples/D3D12HelloWorld/src
D3D12HelloWorld.sln
からVSを起動させます。
そのままではビルドに失敗するので
Solutin Explorerのプロジェクトを右クリックしてプロパティを選び、
GeneralにてTarget Platform Versionを新しい物へ変更します。
私の場合は10.0.10240.0
から10.0.10586.0
へ変更しました。
HelloWindowのプロジェクトが生成した実行ファイルをビルドしてウィンドウが表示されたらOKです。
プロジェクトの作成下見
new projectするとDirectX 12 Appといういかにもなテンプレートが追加されていますが、C++/CLIぽかったのでスルーします。
いつも通りのWin32 Projectで作成します。
パス
DirectX12関連のパスをメモしておきます。
Solutin Explorerのプロジェクトを右クリックしてプロパティを選び
VC++DirectoriesにてIncludeとLibraryを追加します。
Include Directories
C:\Program Files (x86)\Windows Kits\10\Include\10.0.platform番号\um C:\Program Files (x86)\Windows Kits\10\Include\10.0.platform番号\shared
Library Directories
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.platform番号\um\x86
git-flowとhubコマンドを使ってCUIでgithubを活用する
github/hubコマンドを使ってみた - ぷろみんの続きです
概要
git-flowとhubを使います。
インストール
$ sudo apt-get install -y git-flow
初期化
$ mkdir foo $ cd foo # hub導入済み $ git init -g $ git flow init # 質問には全部エンター $ git create $ echo '# foo' >> README.md $ git add . $ git commit -m 'Initial commit' $ git push --all
開発
# issue create [-m <MESSAGE>|-f <FILE>] [-l <LABEL-1>,<LABEL-2>...,<LABEL-N>] $ git issue create -m 'LICENSEを追加する' # issueを解決するブランチを作成する $ git flow feature start add_license
licenseの追加にはliceを使ってみようかと思います。
$ sudo pip install lice $ lice mit > LICENSE
featureブランチでissueを解決し、プッシュします。
$ git add . $ git commit -m 'close #1' $ git flow feature publish add_license
そして、その変更を取り込んでもらえるようにpull-requestを送ります。
$ git pull-request -m "Add license" -b develop -h feature/add_license
問題無ければマージします。
$ git checkout develop
$ git merge https://github.com/YOUR_USER/CURRENT_REPO/pull/2
$ git push origin develop
ここもhubさんの力でgit pr-merge 2
とかできたら良かったんですけどねー。
issueが全て片付いたので、masterへマージします。
$ git checkout master $ git merge develop $ git push origin master
githubで確認すると無事にissueがcloseされました。
参考
terminal - git auto-complete for *branches* at the command line? - Ask Different
github/hubコマンドを使ってみた
概要
githubをCUIで操作できるhubコマンドの使い方や困った事をメモしました。
環境
インストール
まず、ビルドにgoが必要なのでインストールします。
私の場合はansibleで入れました。
こんなややこしい方法取らずに適当な方法でインストールした方が楽です。
# パッケージマネージャから入れる方法 sudo apt-get install -y software-properties-common sudo apt-add-repository -y ppa:ansible/ansible sudo apt-get update sudo apt-get install -y ansible # pipから入れる方法 sudo apt-get install -y python-pip sudo pip install ansible
$ mkdir -p develope/roles $ git clone https://github.com/jlund/ansible-go develope/roles/ansible-go $ vim develope/site.yml
# develope/site.yml --- - hosts: all sudo: yes roles: - ansible-go
$ vim hosts
# ansible_connectionを付けない場合自身のssh鍵が必要 localhost ansible_connection=local
# 接続確認を無効化したい場合 $ vim ansible.cfg [defaults] host_key_checking = false
$ ansible-playbook -i hosts develope/site.yml # 再読み込みしないとgoへのパスが通らないので $ exec $SHELL -l
次はhubのビルド
$ git clone https://github.com/github/hub.git $ cd hub $ ./script/build $ sudo cp hub /usr/local/bin # hubにgitエイリアスをかける $ echo 'eval "$(hub alias -s)"' >> ~/.bash_profile $ exec $SHELL -l $ git version git version 2.1.4 hub version 2.2.0-96-gaa63aa6
push
$ mkdir foo $ cd foo $ git init -g $ echo '# foo' >> README.md $ git create # ここで色々聞かれる
ユーザ名とパスワード、two-factor authenticationを有効にしている場合はSMS等で送られてくるコードを入力します。すると
https://github.com/settings/tokens
に新しくアクセストークンが追加されています。
fooレポジトリも作成されています。
また、~/.config/hub
も生成されています。このファイルにより次回からはgit create
の際に認証が不要になります。
ファイルの内容は以下です。
github.com: - user: YOUR_USER oauth_token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx protocol: https
早速pushしていきましょう。
$ git config --global user.name "YOUR_USER" $ git config --global user.email "YOUR_EMAIL" $ git add . $ git commit -m 'Initial commit' $ git push origin master Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
アクセストークン作ったのならそれでpushして欲しかったのですが、そこはカバーしてくれない様子です。以下の様にすればアクセストークンでpushできるようになるはずですが、せっかく名前とレポジトリを自動取得できるようにしたのに、手入力したくありません。
git remote set-url origin https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@github.com/YOUR_USER/CURRENT_REPO.git
諦めてssh接続します。
ssh-keygen
でid_rsa.pub
を生成し、内容をgithubに登録します。
その後に再トライです。
$ git push origin master
ERROR: Repository not found.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
レポジトリの場所が間違っている様子なので、どこにアクセスしているか確認します。
$ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "origin"] url = git@github.com:/foo.git fetch = +refs/heads/*:refs/remotes/origin/*
url = git@github.com:/foo.git
とユーザ名が抜けてしまっているみたいです。仕方ないので作り直します。
$ rm -rf .git $ git init -g $ git add . $ git commit -m 'Initial commit' $ git push origin master
今度は上手くいきました。
次回はgit-flow
入れてhubを活用してみようと思います。