読者です 読者をやめる 読者になる 読者になる

ぷろみん

プログラミング的な内容を扱ってます

ようやくWindows10にしたのでDX12プログラミングを始めてみた

概要

Windows10にしたらまず最初にすべき事といえば・・・
そう、DirectX12プログラミングですよね。
今回はその導入をやってみたのでメモしておきます。

Visual Studioのアップグレード

始めから入ってない人もここで入れるので一緒です。

Direct3D12 開発環境構築 -プレビュー版- :: ☆PROJECT ASURA☆

ここの手順に従ってインストーラーをDLして実行し、アップグレードが終わった後に変更からWindows SDK10を導入します。

アップグレードの場合は(もしくは最新のビルドでは不要)Windows 10 Developer Preview Toolsはインストール済みでした。

動作確認

Git for WindowsCygwinMinGW等で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

x64だとリンカエラー出ました。

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されました。

参考

git-flow cheatsheet

( WIP: 更新済み ) Ubuntu + Vagrant + Ansible + Serverspec + Capistrano 3 + Git-Flow を使って Nginx + Rails + Unicorn で走るサービスの面倒な作業を自動化しよう! - コードレシピ

terminal - git auto-complete for *branches* at the command line? - Ask Different

licenses/lice · GitHub

github/hubコマンドを使ってみた

概要

githubCUIで操作できるhubコマンドの使い方や困った事をメモしました。

環境

debian

インストール

まず、ビルドに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-keygenid_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を活用してみようと思います。

gitの最新版をビルドする

環境

https://atlas.hashicorp.com/ARTACK/boxes/debian-jessieで作成されたdebianのboxを使っています。

$ sudo aptitude update
$ sudo aptitude -y install git
$ sudo aptitude -y install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev
$ git clone https://github.com/git/git

$ cd git
$ git tag | tail
v2.5.0-rc0
v2.5.0-rc1
v2.5.0-rc2
v2.5.0-rc3
v2.5.1
v2.5.2
v2.5.3
v2.6.0-rc0
v2.6.0-rc1
v2.6.0-rc2
# 2.5.3をインストールすることにする
$ git checkout refs/tags/v2.5.3

# 後はビルドするだけなのでバージョンの古いgitをアンインストールする
$ sudo aptitude -y purge git

$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install

# 環境変数を適用する為にシェルを再起動
$ exec -l $SHELL
$ git --version
git version 2.5.3

Git - Gitのインストールを参考にインストールしましたが、v2は何が違うのでしょうか?

debianでglfwをコンパイルしてwindows向けバイナリを作成する

概要

windows環境での話です。
最近msys-gitやmysy2を使ったりで環境変数やら実行バイナリがごちゃごちゃしてきてしまったので、実験用の環境が欲しくなったので仮想化してみます。

事前準備

管理者権限が必要なパッケージもあります。

  • chocolatly
    https://chocolatey.org/
    サイトに記載されているコマンドを打てばインストールできます。

  • virtual box

$choco install virtualbox
$choco install vagrant
$choco install virtualbox.extensionpack

もしかしたらOpenSSHも必要かもしれません。

choco install openssh

sshはパスが自動で付かないかもしれません。

Windows 8.1ではじめるイマドキの開発環境 - Qiita

vagrant

http://www.vagrantbox.es/から好きなboxを引っ張ってきます。 とりあえずDebianでいきます。

#powershell か msys-mingw
$mkdir debian
$cd debian
$vagrant box add https://atlas.hashicorp.com/ARTACK/boxes/debian-jessie
$vagrant box list
ARTACK/debian-jessie (virtualbox, 8.1.0)
$vagrant init ARTACK/debian-jessie
$vagrant up
$vagrant ssh

Oracle VM VirtualBox Extension Packを入れていないとvagrant upの際に以下のエラーがでます。

The guest machine entered an invalid state while waiting for it
to boot. Valid states are 'starting, running'. The machine is in the
'poweroff' state. Please verify everything is configured
properly and try again.

If the provider you're using has a GUI that comes with it,
it is often helpful to open that and watch the machine, since the
GUI often has more helpful error messages than Vagrant can retrieve.
For example, if you're using VirtualBox, run `vagrant up` while the
VirtualBox GUI is open.

The primary issue for this error is that the provider you're using
is not properly configured. This is very rarely a Vagrant issue.

言われた通りGUIで起動してみます。
するとImplementation of the USB 2.0 controller not found!というエラーが出ます。

ビルド

ここからはvagrantで起動したdebian上での実行例です。

# 必要なパッケージを揃える
$sudo aptitude update
$sudo aptitude -V -D -y install git
$sudo aptitude -V -D -y install cmake
$sudo aptitude -V -D -y install mingw-w64

# mingw版のglfwをビルド
$git clone https://github.com/glfw/glfw
$cd glfw
$cmake -DCMAKE_TOOLCHAIN_FILE=CMake/x86_64-w64-mingw32.cmake .
$make
$sudo make install

# http://www.glfw.org/docs/latest/quick.htmlにあるサンプルをhello.cppとして保存

$x86_64-w64-mingw32-g++ -I/usr/local/include hello.cpp -L/usr/local/lib -lglfw3 -lopengl32 -lwinmm -lgdi32
# windowsとの共有フォルダに実行ファイルを送る
$mv a.exe /vagrant/a.exe

windows側からa.exeを実行すると無事に実行できました。

後片付け

遊び終わったら環境を片付けましょう。

# debian
$exit

# windows
$vagrant halt
$vagrant destroy --force

windows.hが必要ないwindows GUIアプリケーションの作り方

概要

int WINAPI WinMainというエントリポイントにも関わらずヘッダが必要な関数があります。
コンソールアプリケーションでプロジェクトを作るとint main()から始める事ができるが、アプリケーションの動作中ずっと不要なコンソールが出現したままになります。

解決策

まず、Windowsアプリケーションでプロジェクトを作成します。
次にConfiguration Properties -> Linker -> Advanced -> Entry PointmainCRTStartupと書き込みます。

これでint main()で始める事ができて、なおかつ不要なコンソールが出現しません。

Concept Lite(軽量コンセプト)で出来る事

概要

gcc6.0にてConcept Liteのコンパイルができるようになったので、色々と触ってみました。
wandboxを利用すれば簡単に試す事ができます。
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

書き方

conceptはconstexprな関数や変数としても解釈されるので以下の書き方は両方同じ意味になります。

template<class T>
concept bool Pointer = requires(T a){
    *a;
};

// 制約を満たす場合はtrueとなる変数templateとしても機能する
bool a = Pointer<int*>;
template<class T>
concept bool Pointer(){
    return requires(T a){
        *a;
    };
}

// 制約を満たす場合はtrueとなる関数templateとしても機能する
bool a = Pointer<int*>();

コンセプト

コンセプトは型として使う事ができます。
型はautoの様に予測され、制約を満たさない場合はエラーとなります。

template<class T>
concept bool Pointer = requires(T a){
    *a;
};

// concept 'Pointer<int>' was not satisfied
Pointer a = 1;

Pointer b = "test"; // OK

関数の引数に制約を加える場合は以下の記述が可能です。

// 直接指定
void F(Pointer){}

// requires-expression
template<class T>
requires Pointer<T>
void F(T) {}

// 型指定の代わりにコンセプトを記述
template<Pointer T>
void F(T){}

// concept-introduction
Pointer{T}
void F(T){}

simple requirement

template適用後の記述内容にエラーが見つかると制約を満たさなくなります。

template<class T>
concept bool Printable = requires(T a){
    std::cout << a;
};

compound requirement

{}で囲まれた演算の結果の型制約を定義できます。

template<class T>
concept bool Compound = requires(T a){
    {a} -> const char*;
    {*a} -> char;
    {int(*a)} -> int;
};

int main(){
    Compound a = "test";
}

type requirement

必要な型を制約に加える事ができます。

template<class T>
concept bool Type = requires(T a){
    typename T::type;
};

struct X{
    using type = int;
};

int main(){
    Type a = X();
}

以下の記述だとコンセプトを満たしません。

concept bool Type = requires(T a){
    T::type;
};

struct X{
    using type = int;
};

int main(){
    // concept 'Type<X>' was not satisfied
    Type a = X();
}

nested requirement

複数のコンセプトを要求する場合に使います。

// 中身が空はエラーなので書いているだけで、0に意味はない
template<class T>
concept bool A = requires(){ 0; };

template<class T>
concept bool B = requires(){ 0; };

template<class T>
concept bool AB = requires(){
    requires A<T>;
    requires B<T>;
};

コンセプトを満たさない型

struct noncopyable {
    noncopyable() = default;
    noncopyable(const noncopyable&) = delete;
    noncopyable& operator=(const noncopyable&) = delete;
};

//単純に!で否定するとコンセプトを満たさない表現が可能
template<class T>
concept bool Noncopyable = !requires(T a){
    a = a;
};

int main(){
    noncopyable a;
    Noncopyable &b = a;
}

継承関係

継承関係での分岐も簡単に書けます。

struct A;
struct B;

template<class T>
concept bool IsA = requires(T a){ static_cast<A*>(&a); };

template<class T>
concept bool IsB = requires(T a){ static_cast<B*>(&a); };

struct A{};
struct B{};
struct AB: public A, B{};

int main(){
    static_assert(IsA<AB>);
    static_assert(IsB<AB>);
}

mixinの型重複の検出

struct A;
struct B;
struct C;

template<class T>
concept bool IsA = requires(T a){
    static_cast<A*>(&a);
    a.AF();
};

template<class T>
concept bool IsB = requires(T a){
    static_cast<B*>(&a);
    a.BF();
};

template<class T>
concept bool IsC = requires(T a){
    static_cast<C*>(&a);
    a.CF();
};

template<class T>
concept bool IsABC = requires(){
    requires IsA<T>;
    requires IsB<T>;
    requires IsC<T>;
};

struct A{ void AF(){} };
struct B{ void BF(){} };
struct C{ void CF(){} };
struct AB: public A, B{};
struct BC: public B, C{};
// ここでAB::BFとBC::BFがb.BF()として呼ばれ曖昧なのでエラーが出るのでコンセプトIsABCを満たさない
struct ABC: public AB, BC{};

// しかしエラーはいつものconcept 'IsABC<ABC>' was not satisfiedなので原因は分かりにくい

int main(){
    IsABC abc = ABC();
}

型となる可能性があるのでメタ関数の命名規則は使わない方が良さそうですね。

余談

何の問題か分かりませんが以下のコードでinternal compiler errorが出ます。

template<class T>
concept bool Compound = requires(T a){
    {++a} -> T&; 
};

int main(){
    Compound a = 0;
}

参考

N3701 concept lite