はじめに
目的
Macを用いてC++を使っていたのですが、Windowsでも同様に使いたいなと思って環境構築をしたという話です。
自己紹介
しがない大学三年生です。物理系ですがイジングモデルを回す際にC++を使っているだけです。間違ってたらごめんなさい...主に自分が後で見返すためにやったことを整理しただけです。
スペック
僕のではなく、使っているコンピュータの情報を載せておきます。
プロセッサ Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz 2.59 GHz
実装 RAM 16.0 GB
システムの種類 64 ビット オペレーティング システム、x64 ベース プロセッサ
あと編集日は2024/12/9です。最近寒くなってきましたよね。
環境構築
VsCode+MinGW
VsCode+MinGWで環境構築をしました。(VsCode便利だと思うんですけど実験の先生とかTAの方は使ってらっっしゃらないんですよね...)
https://qiita.com/ochx/items/01449d09777187790ee4
に従ってやれば終わりです。まじでわかりやすいです。
タスクの構成
以上を前提にやります。理由は特にないんですが、上の記事で使われているCode Runnerではなく、普通にbuildします。(こっちの方がめんどくさい?)
次の記事のようにしてc_cpp_properties.jsonと、tasks.jsonを作成します。
https://qiita.com/OcoToOo/items/f1d0a125327f5659ad52
一応この記事通りでいいと思いますが、僕のも載せておきます。(FFTW3は後で説明します、というかこれが本題です)
{
"configurations": [
{
"name": "Windows",
"includePath": [
"${workspaceFolder}/**", // プロジェクトのインクルードパス
"C:/libs/fftw/include" // FFTW3 ヘッダーファイルのパス
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"compilerPath": "C:/Program Files (x86)/mingw64/bin/gcc.exe", // MinGW のコンパイラパス (または他のコンパイラ)
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-gcc-x64" // MinGW を使う場合
}
],
"version": 4
}
いろんなところからコピペしてます。(主にchat gptと先の記事とか)
あとはtasks.json:
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe build active file",
"command": "C:\\Program Files (x86)\\mingw64\\bin\\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"-O3",
"-mtune=native",
"-march=native",
"-mfpmath=both",
"-I\"C:/libs/fftw/include\"",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}.exe", // 出力ファイルのパス
"-L\"C:/libs/fftw/lib\"",
"-lfftw3-3",
"-lm"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": "build",
"detail": "compiler: C:\\Program Files (x86)\\mingw64\\bin\\g++.exe"
}
]
}
argsの中身は後で説明するfftwの話と、あとはC++高速化ででてきたおまじないを使っています。(https://qiita.com/kotauchisunsun/items/84e01c6fb621fcc1a647) 注意事項もこの記事にのっているので見てみてはいかがでしょうか。
説明はchatgptが秀逸なのでこれを載せておきます。
c_cpp_properties.json
目的
C++のコード補完やエラー検出(インテリセンス)に使用されるファイルです。
VS Code の C++ 拡張機能が正しく動作するために必要な設定を指定します。
主な役割
ヘッダーファイルの検索パスを指定。
コンパイラのパスを設定。
プロジェクトで使用している標準(例: C++17)やプラットフォームの情報を提供。
主な設定項目
includePath: インテリセンスがヘッダーファイルを検索するパス。
defines: プリプロセッサマクロの定義。
compilerPath: 使用するコンパイラの実行ファイルパス。
要は、エラーを出すためのコードって感じですね。これは別になくてもいいと思います。一方tasks.jsonは実際のコンパイルでのコマンドなどを指定します。またまたchat gptに聞くと、
tasks.json
目的
ビルドや実行などのタスクを自動化するための設定ファイルです。
主にコンパイルやプログラムの実行を設定します。
主な役割
ビルドコマンドや引数の指定。
ターミナルで実行されるコマンドの定義。
主な設定項目
label: タスクの名前。Ctrl+Shift+B でビルド時に選択する際の名前。
command: 実行するプログラムやコマンド(例: g++)。
args: コマンドの引数(例: コンパイルするファイルやフラグ)。
group: タスクの種類(例: build はビルド用)。
problemMatcher: エラーや警告の解析方法。
後は、デバッグについても元記事(再掲:https://qiita.com/OcoToOo/items/f1d0a125327f5659ad52) に載っていますが、これは割愛します。
といっても、segmentation fault(通称:セグフォ)が出てきたとき、エラーの原因が表示されない(大体配列のインデクス外参照が原因)を見つけるのに役に立ったりしてとっっっても便利なんですけどね。
ちなみにデバッグって英語で書くと debug で de は取り除くという意味の接頭辞(increaseとdecreaseとかもそうですよね)と、お馴染みバグを意味する bug の二つで成る英単語です。要は、バグを取り除くためって感じですね。
実際のプログラムの実行は、適当にC++ファイル(test.cppなど)を使って、
#include <iostream>
using namespace std;
int main(){
cout<<"Hello World"<<endl;
}
を入力して、「Ctrl+Shift+B」を押します。(ビルド)
一応写真も張っておきますね(一番左などは、いろいろ拡張機能をダウンロードしてるから少しうるさくなっていますがあまり気にしないでください。あとフォルダ名も。)
英語表記ですが、日本語エディタをダウンロードしていたら日本語になっていると思います。
ここで「Ctrl+Shift+B」を押すと次のような画面になります。
なんか上から出てきたわけですが、何も考えずエンターを押しました。(僕は)
そうすると
下からなんか出てきて以下のような画面になります。なんかエラーが起きてそうならそれをすべてコピペしてchat gptに投げましょう。解決してくれるはずです。
ビルドが終わると、実行ファイル (test.cppなら、test.exe、一般的に名前.cppにたいし、名前.exeが同じフォルダ内に生成されます) が生成されます。
あとは、その実行ファイルがあるディレクトリに移動して(僕は違う場所でずっとやっていたためエラーしか吐かれませんでした)、ターミナルで
'''
.\test.exe
'''
と打つだけです。そうすると出力がでてきます。(今の場合はHello Worldがでてくるはず)
さて、本題に入っていきます。外部ライブラリの導入です。やっぱり、フーリエ変換とかしたくなってくるわけですが(物理系なので)、そのときに高速な外部ライブラリが欲しくなってくるわけです。
外部ライブラリの導入
特に今回はフーリエ変換を行うライブラリfftw3を使えるようにしたいと思います。
fftw3を使う方法はVisual Studioを使ったりだとか、MSYS2を使ったりだとかいろいろありましたが、最もシンプルだと思われる方法で導入します。(fftw3以外に新たなものをダウンロードしないという意味でですが。もし脆弱性とかあったらごめん。)
インストール
ここではWindows向けに解説します。
といってもMacはめちゃくちゃ簡単で、homebrewを使ってダウンロードするだけです。ただ、ある場所のライブラリをtasks.jsonにて指定する必要があります。(https://formulae.brew.sh/formula/fftw の通りにします。もちろんhomebrewを入れていることは前提です)
さて、話を戻すと、https://fftw.org/install/windows.html にて64-bit version: fftw-3.3.5-dll64.zip (3.1MB) (2024/12/9時点)をインストールします。
(ここ5年のパソコンを使っているならたいていの人は64-bitだと思いますが32-bitならもう一つをインストールしてください。)
ダウンロードしたら、これはzipファイルなので「すべて展開」を押してください(右クリックでもでてきますし、探せばどこかにあります。
展開できたら新たにフォルダができると思います。(上の写真で薄い青の3つ下にできてますね)
さて、ここでfftw3を使うには、C++の実行コマンド(tasks.jsonのargsのところ)でライブラリなどを指定+パスを通す必要があります。
まずは、そういったライブラリをおくフォルダlibsをCドライブ直下につくります。(青で選択しているところは今作りました)
さらにinclude,bin,libフォルダをつくります。(binはなくてもいいらしい)
そして、展開したフォルダの中から、fftw3というのを見つけて、
includeフォルダの中にコピーします。
注意なんですが、fftw3と書いてはいてもこれは fftw3.h というヘッダファイルです。無知な僕は、それをしらずfftw3.hがない!とひたすら騒いでました。
そして、.dllというファイルも3つとも選択し、
こちらはlibフォルダに移動しておきます。
binにはwisdomとかを配置するらしいですが詳しくはわからないので割愛します。
それぞれをまとめるとこんな感じらしいです(chatgpt)
C:\libs
├── fftw
│ ├── include (for header files)
│ ├── lib (for static or import libraries: .lib/.a files)
│ ├── bin (for DLLs or executables)
家を建てる場合を考えると:
include: 設計図(ライブラリの使い方を示すヘッダーファイル)。
lib: あらかじめ作られた部品(ライブラリの機能を実装するファイル)。
bin: 工具や外部機械(実行時に必要なDLLや共有ライブラリ)。
ということらしいです。
パスを通す
今回の場合は、libにパスを通す必要があります。
設定アプリ→システム(左のところに並んでます)→バージョン仕様(一番下)→システムの詳細設定(小さい赤文字)→環境変数→システム環境変数の中にPathという項目があるのでクリックして、編集をおす→新規を押して、libのパスを書き込む。(上のように作っているならば書き込むのはC:\libs\fftw\libになります。)
わかりずらかったら、適当に調べてみてください。
tasks.jsonの編集
最初のように書いてください(tasks.jsonのargsの部分の抜粋)
"args": [
"-fdiagnostics-color=always",
"-g",
"-O3",
"-mtune=native",
"-march=native",
"-mfpmath=both",
"-I\"C:/libs/fftw/include\"",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}.exe", // 出力ファイルのパス
"-L\"C:/libs/fftw/lib\"",
"-lfftw3-3",
"-lm"
],
ライブラリのインクルードは
"-I\"C:/libs/fftw/include\"",
です。パスが違う場合は、とにかくfftw3を置いた場所へのpathを書き込みましょう。外側にクオーテーションついている理由はわかりません。ごめんなさい。
"-L\"C:/libs/fftw/lib\"",
"-lfftw3-3",
これも同様です。気を付けるべきなのは"-lfftw3-3"は、libファイルに移動したファイル(から.dll)を抜いたものに対応しています。精度を変える場合はここをいじる必要があるかもしれません。
以上で動くはずです。
#include <fftw3.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int N = 8;
fftw_complex *in, *out;
fftw_plan p;
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
for (int i = 0; i < N; i++) {
in[i][0] = i; // Real part
in[i][1] = 0; // Imaginary part
}
p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(p);
printf("FFT result:\n");
for (int i = 0; i < N; i++) {
printf("%f + %fi\n", out[i][0], out[i][1]);
}
fftw_destroy_plan(p);
fftw_free(in);
fftw_free(out);
return 0;
}
でも試してみてください。
エラーが出たらchat gptに聞いてください。
では。