やりたかったこと
以前、IfcOpenShell pythonバインディングのことはじめで、condaでのIfcOpenShellのPythonバインディングを入れる解説をしましたが、何度やってもうまくいったりいかなかったりします。
最近はC++を触ることも多いので、この際、ソースからビルドしてみることにしました。環境はWindows 10、Visual Studio 2019 Communityです。これをやると、自動的にPythonバインディングも生成されます。
準備
まずは、ifcOpenShellでGithubのサイトで最新のコードをダウンロードしておきます。同サイトに要件なども書いてあります。Visual Studioの他にCMakeもインストールしてパスを通しておきましょう。作業を進めるには、Developer Command Promptが必要です。Visual Studioをインストールしたらついてくると思います。
ダウンロードして解凍したら、上記のコマンドプロンプトを使って、当該フォルダに移動します。その中にwinというフォルダがあるので、そこまで移動します。
コンパイル
詳細はwinフォルダのreadme.mdに書いてあるのですが、ここでは1つのやり方を示しておきます。ビルドに関して、IfcOpenShellは64ビットが推奨されるとのことです。理由はIFCは容易に2Gを超えるからとあります。また、何も指定しないとDebug用のビルドになりますが、今回はReleaseとしています。
最初のbuild-deps.cmd以外は、最初のパラメータがキャッシュ変数で保存されるはずなのですが、全て指定しないとうまくいきませんでした。
cd win
# 依存ファイルのダウンロード、ビルド
build-deps.cmd vs2019-x64 Release
# CMakeによりVisual Studioのソリューションファイルを作成
run-cmake.bat vs2019-x64 Release
# コマンドでVisual Studioのソリューションのビルド
build-ifcopenshell.bat vs2019-x64 Release
# フォルダにインストール
install-ifcopenshell.bat vs2019-x64 Release
うまくいくと、IfcOpenShell
のフォルダに_installed-vs2019-x64
が生成されており、bin/include/lib
があることが分かります。必要に応じてDebugも作るとよいと思います。
サンプルプログラムの実行
インストールされたライブラリを使ってみます。今回はCMakeでコンパイルしてみようと思います。ただ、CMakeで生成しているにも関わらず、CMakeのConfigがありません。ドキュメントにも手動で参照してねと書いてあります。なんて面倒な、、、
CMakeする
今回は汎用的にCMakeでビルドしてみます。いくつか注意することがあって、上記のインストールプロセスで、CRTの設定が静的リンクをすることになっています。ここ を参考に切り替えを自動化するようにしておきます。対象するソースコードはmain.cpp
です。
project(main)
cmake_minimum_required(VERSION 3.14)
# Visual Studioでのコンパイル時は、CRTライブラリを静的リンクさせる
if(MSVC)
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
string(REPLACE "/W3" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /EHsc")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /DBUILD_TYPE=\\\"Debug\\\"")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /DBUILD_TYPE=\\\"Release\\\"")
endif(MSVC)
set(IFCOPENSHELL_ROOT "IfcOpenShellのインストールフォルダ")
find_package(BOOST REQUIRED)
add_executable(main main.cpp)
target_include_directories(main PRIVATE
${IFCOPENSHELL_ROOT}\\include
${Boost_INCLUDE_DIRS}
)
target_link_directories(main PRIVATE ${IFCOPENSHELL_ROOT}\\lib)
target_link_libraries(main PRIVATE IfcGeom IfcGeom_ifc2x3 IfcGeom_ifc4 IfcParse)
以下はサンプルプログラムを少し変えたものです。
対象のIFCファイルから、IfcBuildingElementを抜いてきて、IfcWindowに該当するものは面積を計算しています。デバッグコンソールが文字化けするので、対処するためのコードを入れています。
# include <iostream>
# include <string>
# include <windows.h>
# define IfcSchema Ifc2x3
# include "ifcparse/IfcFile.h"
# include "ifcparse/Ifc2x3.h"
int main(int argc, char** argv) {
std::string path = "";
if (argc != 2) {
path = "適当なifcファイルのパス";
}
else {
path = argv[1];
}
// コマンドプロンプトのコードページを保存
UINT prevCP = GetConsoleOutputCP();
// コードページをUTF-8に変更
SetConsoleOutputCP(CP_UTF8);
// Redirect the output (both progress and log) to stdout
Logger::SetOutput(&std::cout,&std::cout);
// Parse the IFC file provided in argv[1]
IfcParse::IfcFile file(path);
if (!file.good()) {
std::cout << "Unable to parse .ifc file" << std::endl;
return 1;
}
IfcSchema::IfcBuildingElement::list::ptr elements = file.instances_by_type<IfcSchema::IfcBuildingElement>();
std::cout << "Found " << elements->size() << " elements in " << path << ":" << std::endl;
for (IfcSchema::IfcBuildingElement::list::it it = elements->begin(); it != elements->end(); ++it) {
const IfcSchema::IfcBuildingElement* element = *it;
IfcEntityInstanceData data = element->data();
std::cout << element->data().toString() << std::endl;
const IfcSchema::IfcWindow* window;
if ((window = element->as<IfcSchema::IfcWindow>()) != 0) {
if (window->hasOverallWidth() && window->hasOverallHeight()) {
const double area = window->OverallWidth() * window->OverallHeight();
std::cout << "The area of this window is " << area << std::endl;
}
}
}
// コードページを元に戻す(これをやらないとコマンドプロンプトを開き直すまでUTF-8のままになる)
SetConsoleOutputCP(prevCP);
}
Visual Studioでコンパイル
準備ができたら、cmakeをしてください。うまくいけば、main.sln
ができていると思います。
なお、CMakeでの設定がうまくいっていれば、以下のように「ランタイムライブラリ」が`マルチスレッド(/MT)となっているはずです(Debugの場合は/MTd)。