mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-18 19:30:25 +00:00
a68113474b
A coverage-guided libFuzzer harness (src/ifcfuzz/ifcparse_fuzzer.cpp) that constructs IfcFile directly from in-memory input and calls toString() on every parsed instance to force full lazy attribute evaluation, rather than only observing IfcConvert's exit code from a fuzzed subprocess. Gated behind a new BUILD_FUZZERS option (OFF by default) so it has no effect on existing builds; enabling it requires a Clang toolchain built with -fsanitize=fuzzer. -fsanitize=fuzzer itself stays scoped to the one new target rather than going into the global compiler flags, since it supplies its own main() and would otherwise break every other target including CMake's own compiler checks. Already found and fixed three real bugs this way: two null-pointer dereferences (in header parsing and reference resolution) and a leak of IfcSpfLexer on early return/exception during file scanning. See src/ifcfuzz/README.md for build and usage instructions.
812 lines
32 KiB
CMake
812 lines
32 KiB
CMake
################################################################################
|
|
# #
|
|
# This file is part of IfcOpenShell. #
|
|
# #
|
|
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
|
# it under the terms of the Lesser GNU General Public License as published by #
|
|
# the Free Software Foundation, either version 3.0 of the License, or #
|
|
# (at your option) any later version. #
|
|
# #
|
|
# IfcOpenShell is distributed in the hope that it will be useful, #
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
# Lesser GNU General Public License for more details. #
|
|
# #
|
|
# You should have received a copy of the Lesser GNU General Public License #
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
|
# #
|
|
################################################################################
|
|
|
|
cmake_minimum_required(VERSION 3.21)
|
|
if (NOT DEFINED CMAKE_CXX_STANDARD)
|
|
set(CMAKE_CXX_STANDARD 17)
|
|
endif()
|
|
if (CMAKE_CXX_STANDARD LESS 17)
|
|
message(FATAL_ERROR "C++17 or newer is required.")
|
|
endif()
|
|
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
|
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
|
|
# The VERSION file in the repository root is the single source of truth for the
|
|
# release version. Read it unconditionally so a plain source build reports the
|
|
# real version through buildinfo.cpp instead of the stale hardcoded 0.8.0
|
|
# fallback (see #8164). VERSION_OVERRIDE still controls the branch name used
|
|
# when ADD_COMMIT_SHA embeds a commit sha.
|
|
file(READ "../VERSION" "RELEASE_VERSION_")
|
|
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
|
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
|
|
|
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
|
|
|
if(POLICY CMP0141) # 3.25+
|
|
cmake_policy(SET CMP0141 NEW) # Support for `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`.
|
|
endif()
|
|
if(POLICY CMP0144) # 3.27
|
|
cmake_policy(SET CMP0144 NEW) # find_package() uses upper-case <PACKAGENAME>_ROOT variables.
|
|
endif()
|
|
if(POLICY CMP0167) # 3.30
|
|
cmake_policy(SET CMP0167 OLD)
|
|
endif()
|
|
|
|
if(NOT CMAKE_BUILD_TYPE)
|
|
set(CMAKE_BUILD_TYPE "Release")
|
|
endif()
|
|
|
|
# Include utility macros and functions
|
|
include(utilities.cmake)
|
|
|
|
# use extra version to make pre-release using eg semver
|
|
if(NOT DEFINED EXTRA_VERSION)
|
|
set(EXTRA_VERSION "-alpha.3")
|
|
endif()
|
|
|
|
option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF)
|
|
option(WASM_BUILD "Build a WebAssembly binary." OFF)
|
|
|
|
option(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
|
option(BUILD_SHARED_LIBS "Build IfcOpenShell as shared libraries (required)." ON)
|
|
option(MSVC_PARALLEL_BUILD "Multi-threaded compilation in Microsoft Visual Studio (/MP)" OFF)
|
|
option(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
|
|
option(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
|
|
option(NO_WARN "Disable all warnings" OFF)
|
|
option(CREATE_BUNDLE "Copy .so files and don't create RPATHS or SOVERSION symlinks" )
|
|
|
|
option(BUILD_IFCGEOM "Build IfcGeom." ON)
|
|
option(BUILD_IFCPYTHON "Build IfcPython." ON)
|
|
option(BUILD_IFCPARSE_EXPERIMENTAL_WRAPPER "Build the experimental Clang-generated ifcparse Python wrapper." OFF)
|
|
option(BUILD_CONVERT "Build IfcConvert executable." ON)
|
|
option(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF)
|
|
option(BUILD_EXAMPLES "Build example applications." ON)
|
|
option(BUILD_GEOMSERVER "Build IfcGeomServer executable (Open CASCADE is required)." ON)
|
|
option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF)
|
|
option(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) # QtViewer requires Qt6
|
|
option(BUILD_IFCMODEL_UI "Build minimal Qt IFC model UI prototype" OFF)
|
|
option(BUILD_BONSAIVIEWER "Build Bonsai Viewer" OFF) # Requires Qt6 + OpenGL 4.5
|
|
option(BUILD_IFCOPENSHELL_PARSE_TESTS "Build C++ unit tests for IfcParse (fetches Catch2 v3)" OFF)
|
|
option(BUILD_IFCOPENSHELL_GEOMETRY_TESTS "Build C++ unit tests for IfcGeom (fetches Catch2 v3)" OFF)
|
|
option(BUILD_BONSAIVIEWER_TESTS "Build unit tests for Bonsai Viewer core (fetches Catch2 v3)" OFF)
|
|
option(BUILD_BONSAIVIEWER_WGPU "Build the experimental wgpu backend (fetches wgpu-native binary release)" OFF)
|
|
# IfcViewer (the GL static lib) now links against IfcViewerWgpu because
|
|
# SceneLoader drives the wgpu viewport. Auto-enable the wgpu subproject
|
|
# whenever BUILD_BONSAIVIEWER is on so the link target exists.
|
|
if(BUILD_BONSAIVIEWER AND NOT BUILD_BONSAIVIEWER_WGPU)
|
|
message(STATUS "BUILD_BONSAIVIEWER implies BUILD_BONSAIVIEWER_WGPU "
|
|
"(SceneLoader uses ViewportWindow); auto-enabling.")
|
|
set(BUILD_BONSAIVIEWER_WGPU ON)
|
|
endif()
|
|
option(BUILD_PACKAGE "" OFF)
|
|
|
|
option(
|
|
BUILD_FUZZERS
|
|
"Build libFuzzer security-fuzzing harnesses. Requires a Clang toolchain configured with -fsanitize=fuzzer (typically also address,undefined) via CMAKE_CXX_FLAGS."
|
|
OFF
|
|
)
|
|
option(
|
|
IFCOPENSHELL_DEPLOY_QT_RUNTIME
|
|
"Deploy Qt runtime dependencies for installed Qt applications."
|
|
ON
|
|
)
|
|
option(
|
|
IFCOPENSHELL_DEPLOY_QT_TRANSLATIONS
|
|
"Deploy Qt translation catalogs with installed Qt applications."
|
|
OFF
|
|
)
|
|
|
|
option(WITH_OPENCASCADE "Enable geometry interpretation using Open CASCADE" ON)
|
|
option(WITH_CGAL "Enable geometry interpretation using CGAL" ON)
|
|
option(WITH_MANIFOLD "Enable geometry interpretation using Manifold" OFF)
|
|
option(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
|
|
option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
|
|
option(WITH_PROJ "Enable output of Earth-Centered Earth-Fixed glTF output using the PROJ library" OFF)
|
|
option(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF)
|
|
option(WITH_ROCKSDB "Support a RocksDB key-value store as a file backend in IfcOpenShell" OFF)
|
|
option(WITH_ZSTD "Use Zstd compression in RocksDB writes" OFF)
|
|
|
|
option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF)
|
|
option(USE_DEBUG_PYTHON "Use debug binaries when building Debug IfcPython on Windows." OFF)
|
|
option(ADD_COMMIT_SHA "Add commit sha and branch in version number, requires git" OFF)
|
|
option(VERSION_OVERRIDE "Override the version defined in buildinfo.cpp with the file VERSION in the repository root" OFF)
|
|
|
|
set(
|
|
PYTHON_MODULE_INSTALL_DIR
|
|
"" CACHE PATH
|
|
"Directory to install IfcPython package to. By default package is installed in found Python's site-packages."
|
|
)
|
|
|
|
if (VERSION_OVERRIDE)
|
|
file(READ "../VERSION" "RELEASE_VERSION_")
|
|
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
|
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
|
else()
|
|
set(RELEASE_VERSION "0.8.0")
|
|
endif()
|
|
|
|
project(IfcOpenShell VERSION ${RELEASE_VERSION})
|
|
|
|
# Make sure CMake modules in this project are found first
|
|
list(PREPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
|
|
|
|
# Catch2 is fetched only when an explicit C++ test family is enabled, so the
|
|
# default build remains offline-capable.
|
|
if(BUILD_IFCOPENSHELL_PARSE_TESTS OR BUILD_IFCOPENSHELL_GEOMETRY_TESTS OR BUILD_BONSAIVIEWER_TESTS)
|
|
include(FetchContent)
|
|
FetchContent_Declare(
|
|
Catch2
|
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
|
GIT_TAG v3.5.4
|
|
GIT_SHALLOW TRUE
|
|
)
|
|
FetchContent_MakeAvailable(Catch2)
|
|
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
|
include(CTest)
|
|
include(Catch)
|
|
enable_testing()
|
|
endif()
|
|
|
|
if(MINIMAL_BUILD)
|
|
message(STATUS "Setting options for minimal build")
|
|
set(BUILD_GEOMSERVER OFF)
|
|
set(BUILD_IFCPYTHON OFF)
|
|
set(WITH_CGAL OFF)
|
|
set(COLLADA_SUPPORT OFF)
|
|
set(GLTF_SUPPORT OFF)
|
|
set(USD_SUPPORT OFF)
|
|
endif()
|
|
|
|
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND(NOT BUILD_IFCGEOM))
|
|
message(STATUS "'IfcGeom' is required with current outputs")
|
|
set(BUILD_IFCGEOM ON)
|
|
endif()
|
|
|
|
find_program(CCACHE_FOUND ccache)
|
|
if(CCACHE_FOUND)
|
|
message(STATUS "`ccache` is found, using it as a compiler launcher.")
|
|
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
|
|
if(MSVC)
|
|
# By default Visual Studio generators will use /Zi which is not compatible
|
|
# with ccache, so tell Visual Studio to use /Z7 instead.
|
|
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
|
|
# Not needed for Ninja.
|
|
if(CMAKE_GENERATOR MATCHES "Visual Studio")
|
|
file(COPY_FILE
|
|
${CCACHE_FOUND} ${CMAKE_BINARY_DIR}/cl.exe
|
|
ONLY_IF_DIFFERENT)
|
|
set(CMAKE_VS_GLOBALS
|
|
"CLToolExe=cl.exe"
|
|
"CLToolPath=${CMAKE_BINARY_DIR}"
|
|
"UseMultiToolTask=true"
|
|
)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(MSVC AND MSVC_PARALLEL_BUILD)
|
|
add_definitions("/MP")
|
|
endif()
|
|
|
|
if(NO_WARN)
|
|
if(MSVC)
|
|
add_compile_options("/w")
|
|
else()
|
|
add_compile_options("-w")
|
|
endif()
|
|
endif()
|
|
|
|
include(GNUInstallDirs)
|
|
|
|
if(NOT INCLUDEDIR)
|
|
set(INCLUDEDIR include)
|
|
endif()
|
|
if(NOT IS_ABSOLUTE ${INCLUDEDIR})
|
|
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
|
endif()
|
|
message(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
|
|
|
|
if(MSVC)
|
|
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
|
|
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
|
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
|
add_definitions(-wd4251)
|
|
endif()
|
|
|
|
UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT)
|
|
UNIFY_ENVVARS_AND_CACHE(BOOST_LIBRARYDIR)
|
|
|
|
if(NOT MINIMAL_BUILD)
|
|
UNIFY_ENVVARS_AND_CACHE(PYTHON_INCLUDE_DIR)
|
|
UNIFY_ENVVARS_AND_CACHE(PYTHON_LIBRARY)
|
|
UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE)
|
|
endif()
|
|
|
|
# Get a list of all OPTION flags from the CMakeLists.txt
|
|
get_all_option_flags(option_flags)
|
|
|
|
# Loop through the list of OPTION flags and convert the corresponding environment variables
|
|
foreach(option_flag IN LISTS option_flags)
|
|
convert_env_var_to_bool("${option_flag}")
|
|
endforeach()
|
|
|
|
if(WITH_CGAL)
|
|
find_package(CGAL REQUIRED)
|
|
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_CGAL)
|
|
list(APPEND GEOMETRY_KERNELS cgal)
|
|
endif()
|
|
|
|
if(BUILD_IFCGEOM AND WITH_OPENCASCADE)
|
|
find_package(OpenCASCADE REQUIRED)
|
|
# Map OpenCASCADE_LIBRARIES variable from OpenCASCADEConfig.cmake to OpenCASCADE_LIBRARIES used by kernel generic cmake file
|
|
set(OpenCASCADE_LIBRARIES ${OpenCASCADE_LIBRARIES})
|
|
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_OPENCASCADE)
|
|
list(APPEND GEOMETRY_KERNELS opencascade)
|
|
endif()
|
|
|
|
message(STATUS "BUILD_IFCGEOM WITH_MANIFOLD: ${BUILD_IFCGEOM} ${WITH_MANIFOLD}")
|
|
|
|
if(BUILD_IFCGEOM AND WITH_MANIFOLD)
|
|
find_package(manifold CONFIG REQUIRED)
|
|
if(TARGET manifold::manifold)
|
|
set(MANIFOLD_LIBRARIES manifold::manifold)
|
|
elseif(TARGET manifold)
|
|
set(MANIFOLD_LIBRARIES manifold)
|
|
else()
|
|
message(FATAL_ERROR "Unable to determine manifold target")
|
|
endif()
|
|
list(APPEND GEOMETRY_KERNELS manifold)
|
|
endif()
|
|
|
|
if(BUILD_IFCGEOM)
|
|
list(APPEND GEOMETRY_KERNELS passthrough)
|
|
endif()
|
|
|
|
if(GLTF_SUPPORT)
|
|
find_package(nlohmann_json REQUIRED)
|
|
endif()
|
|
|
|
# Add USD support to serializers
|
|
if(USD_SUPPORT)
|
|
find_package(USD REQUIRED)
|
|
endif(USD_SUPPORT)
|
|
|
|
if (WITH_ROCKSDB)
|
|
# Temporaily mess with CMAKE_FIND_PACKAGE_PREFER_CONFIG to help RocksDB
|
|
# find it's zstd dependency on Windows.
|
|
# Only do it on Windows, otherwise it might create problems as
|
|
# findzstd and zstd-config target names do not match.
|
|
if(WIN32)
|
|
set(TEMP CMAKE_FIND_PACKAGE_PREFER_CONFIG)
|
|
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
|
|
endif()
|
|
find_package(RocksDB CONFIG REQUIRED)
|
|
if(WIN32)
|
|
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ${TEMP})
|
|
endif()
|
|
|
|
message(STATUS "RocksDB: found at '${RocksDB_DIR}'.")
|
|
add_library(IFCOPENSHELL_RocksDB INTERFACE)
|
|
set(IFCOPENSHELL_ROCKSDB_TARGET IFCOPENSHELL_RocksDB)
|
|
set(ROCKSDB_LIBRARIES "IFCOPENSHELL_RocksDB")
|
|
target_compile_definitions(IFCOPENSHELL_RocksDB INTERFACE IFOPSH_WITH_ROCKSDB)
|
|
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_ROCKSDB)
|
|
# See https://github.com/facebook/rocksdb/issues/981.
|
|
if(TARGET RocksDB::rocksdb)
|
|
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb)
|
|
elseif(TARGET RocksDB::rocksdb-shared)
|
|
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb-shared)
|
|
else()
|
|
message(FATAL_ERROR "RocksDB found but neither RocksDB::rocksdb nor RocksDB::rocksdb-shared target exists")
|
|
endif()
|
|
|
|
if (WITH_ZSTD)
|
|
# @todo do we actually need the zstd include dir or rather just pass
|
|
# the libzstd.a along with the rocksdb library when needed and feature
|
|
# detect based on rocksdb API?
|
|
find_package(zstd CONFIG REQUIRED)
|
|
message(STATUS "zstd: found at '${zstd_DIR}'.")
|
|
endif()
|
|
endif()
|
|
|
|
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
|
|
# runtime, when doing running conda-build we pick what conda prepared for us.
|
|
if(WIN32 AND("$ENV{CONDA_BUILD}" STREQUAL ""))
|
|
set(Boost_USE_STATIC_LIBS ON)
|
|
set(Boost_USE_STATIC_RUNTIME OFF)
|
|
set(Boost_USE_MULTITHREADED ON)
|
|
|
|
# Disable Boost's autolinking as the libraries to be linked to are supplied
|
|
# already by CMake, and wrong libraries would be asked for when code is
|
|
# compiled with a toolset different from default.
|
|
if(MSVC)
|
|
add_definitions(-DBOOST_ALL_NO_LIB)
|
|
|
|
# Necessary for boost version >= 1.67
|
|
set(BCRYPT_LIBRARIES "bcrypt.lib")
|
|
endif()
|
|
else()
|
|
# Disable Boost's autolinking as the libraries to be linked to are supplied
|
|
# already by CMake, and it's going to conflict if there are multiple, as is
|
|
# the case in conda-forge's libboost feedstock.
|
|
add_definitions(-DBOOST_ALL_NO_LIB)
|
|
|
|
if(WIN32)
|
|
# Necessary for boost version >= 1.67
|
|
set(BCRYPT_LIBRARIES "bcrypt.lib")
|
|
endif()
|
|
endif()
|
|
|
|
if(WASM_BUILD)
|
|
set(BOOST_COMPONENTS)
|
|
else()
|
|
# @todo review this, shouldn't this be all possible header-only now?
|
|
# ... or rewritten using C++17 features?
|
|
# set(BOOST_COMPONENTS system program_options regex thread date_time iostreams)
|
|
set(BOOST_COMPONENTS program_options regex thread date_time iostreams)
|
|
endif()
|
|
|
|
if(USE_MMAP)
|
|
if(MSVC)
|
|
# filesystem is necessary for the utf-16 wpath
|
|
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams filesystem)
|
|
else()
|
|
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams)
|
|
endif()
|
|
endif()
|
|
|
|
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
|
message(STATUS "Boost include files found in ${Boost_INCLUDE_DIRS}")
|
|
message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
|
|
|
|
if(COLLADA_SUPPORT)
|
|
find_package(OpenCOLLADA REQUIRED)
|
|
endif()
|
|
|
|
if(ENABLE_BUILD_OPTIMIZATIONS)
|
|
if(MSVC)
|
|
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
|
|
# with the exception with RelWithDebInfo has /Ob1 instead. /Ob2 has been observed to improve the performance
|
|
# of IfcConvert significantly.
|
|
# TODO Setting of /GL and /LTCG don't seem to apply for static libraries (IfcGeom, IfcParse)
|
|
# C++
|
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /GL")
|
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
|
|
|
|
# Linker
|
|
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
|
|
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
|
|
|
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
|
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
|
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
|
else()
|
|
# GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here?
|
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
|
endif()
|
|
else()
|
|
# @tfk I commented this out as this kind of defeats the purpose of RelWithDebInfo. For the
|
|
# best debugging experience simply use Debug. Note that in MSVC you can selectively toggle
|
|
# optimization on a specific file if you're investigating a specific issue.
|
|
# if(MSVC)
|
|
# set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od")
|
|
# endif()
|
|
endif(ENABLE_BUILD_OPTIMIZATIONS)
|
|
|
|
if(MSVC)
|
|
# warning due to virtual inheritance
|
|
add_definitions(-wd4250)
|
|
# warning due to select definitions in the schema being redundant
|
|
add_definitions(-wd4584)
|
|
|
|
# didn't work well on ifcopenbot, @todo make configurable
|
|
# add_definitions(/MP)
|
|
|
|
# Enable solution folders (free VS versions prior to 2012 don't support solution folders)
|
|
if(MSVC_VERSION GREATER 1600)
|
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
|
endif()
|
|
|
|
if(USE_VLD)
|
|
add_definitions(-DUSE_VLD)
|
|
endif()
|
|
|
|
# Enforce Unicode for CRT and Win32 API calls
|
|
add_definitions(-D_UNICODE -DUNICODE)
|
|
|
|
# Disable warnings about unsafe C functions; we could use the safe C99 & C11 versions if we have no need for supporting old compilers.
|
|
add_definitions(-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS)
|
|
add_definitions(-bigobj) # required for building the big ifcXXX.objs, https://msdn.microsoft.com/en-us/library/ms173499.aspx
|
|
|
|
# Bump up the warning level from the default 3 to 4.
|
|
add_definitions(-W4)
|
|
|
|
if(MSVC_VERSION GREATER 1800) # > 2013
|
|
# Disable overeager and false positives causing C4458 ("declaration of 'indentifier' hides class member"), at least for now.
|
|
add_definitions(-wd4458)
|
|
endif()
|
|
|
|
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
|
|
if(MSVC_VERSION GREATER 1900 AND(Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
|
add_definitions(-permissive-)
|
|
endif()
|
|
|
|
# Link against the static VC runtime
|
|
# TODO Make this configurable
|
|
# if("$ENV{CONDA_BUILD}" STREQUAL "")
|
|
# foreach(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
|
|
# CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
|
# CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
|
# if(${flag} MATCHES "/MD")
|
|
# STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
|
|
# endif()
|
|
# if(${flag} MATCHES "/MDd")
|
|
# STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
|
|
# endif()
|
|
# endforeach()
|
|
# endif()
|
|
|
|
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
|
|
# See #5158.
|
|
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.40)
|
|
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
|
endif()
|
|
else()
|
|
add_definitions(-Wall -Wextra)
|
|
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
add_definitions(-Wno-tautological-constant-out-of-range-compare)
|
|
else()
|
|
add_definitions(-Wno-maybe-uninitialized)
|
|
endif()
|
|
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0))
|
|
# OpenCascade spews a lot of deprecated-copy warnings
|
|
add_definitions(-Wno-deprecated-copy)
|
|
endif()
|
|
|
|
# -fPIC is not relevant on Windows and creates pointless warnings
|
|
if(UNIX)
|
|
add_definitions(-fPIC)
|
|
endif()
|
|
endif(MSVC)
|
|
|
|
include_directories(${INCLUDE_DIRECTORIES}
|
|
${Boost_INCLUDE_DIRS}
|
|
${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR}
|
|
)
|
|
|
|
if(NOT SCHEMA_VERSIONS)
|
|
if(WASM_BUILD)
|
|
# super arbitrarily try to keep size down at least a little bit
|
|
set(SCHEMA_VERSIONS "2x3" "4" "4x3_add2")
|
|
else()
|
|
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3" "4x3_tc1" "4x3_add1" "4x3_add2")
|
|
endif()
|
|
endif()
|
|
|
|
message(STATUS "IFC SCHEMA_VERSIONS that will be used for the build: ${SCHEMA_VERSIONS}.")
|
|
|
|
if(COMPILE_SCHEMA)
|
|
# @todo, this appears to be untested at the moment
|
|
find_package(PythonInterp)
|
|
|
|
if(NOT PYTHONINTERP_FOUND)
|
|
message(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
|
|
endif()
|
|
|
|
set(IFC_RELEASE_NOT_USED ${SCHEMA_VERSIONS})
|
|
|
|
# Install pyparsing if necessary
|
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
|
|
|
if("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
|
execute_process(COMMAND pip freeze OUTPUT_VARIABLE PYTHON_PACKAGE_LIST)
|
|
|
|
if("${PYTHON_PACKAGE_LIST}" STREQUAL "")
|
|
message(WARNING "Failed to find pip. Pip is required to automatically install pyparsing")
|
|
endif()
|
|
endif()
|
|
|
|
string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND)
|
|
|
|
if("${PYPARSING_FOUND}" STREQUAL "-1")
|
|
message(STATUS "Installing pyparsing")
|
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
|
|
|
if(NOT "${SUCCESS}" STREQUAL "0")
|
|
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
|
|
|
if(NOT "${SUCCESS}" STREQUAL "0")
|
|
message(WARNING "Failed to automatically install pyparsing. Please install manually")
|
|
endif()
|
|
endif()
|
|
else()
|
|
message(STATUS "Python interpreter with pyparsing found")
|
|
endif()
|
|
|
|
# Bootstrap the parser
|
|
message(STATUS "Compiling schema, this will take a while...")
|
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
|
WORKING_DIRECTORY ../src/ifcexpressparser
|
|
OUTPUT_FILE express_parser.py
|
|
RESULT_VARIABLE SUCCESS)
|
|
|
|
if(NOT "${SUCCESS}" STREQUAL "0")
|
|
message(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
|
|
endif()
|
|
|
|
# Generate code
|
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
|
WORKING_DIRECTORY ../src/ifcparse
|
|
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
|
|
|
|
# Prevent the schema that had just been compiled from being excluded
|
|
foreach(schema ${SCHEMA_VERSIONS})
|
|
if("${COMPILED_SCHEMA_NAME}" STREQUAL "${schema}")
|
|
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${schema}")
|
|
endif()
|
|
endforeach()
|
|
endif(COMPILE_SCHEMA)
|
|
|
|
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
|
|
if(NOT Boost_VERSION LESS 105800)
|
|
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
|
|
endif()
|
|
|
|
add_subdirectory(../src/plugin plugin)
|
|
|
|
add_subdirectory(../src/ifcparse ifcparse)
|
|
set(IFCOPENSHELL_LIBRARIES IfcParse)
|
|
if(BUILD_IFCOPENSHELL_PARSE_TESTS)
|
|
add_subdirectory(../src/ifcparse/tests ifcparse/tests)
|
|
endif()
|
|
|
|
if(BUILD_EXAMPLES OR BUILD_BONSAIVIEWER)
|
|
add_subdirectory(../src/helpers helpers)
|
|
endif()
|
|
|
|
if(BUILD_IFCPARSE_EXPERIMENTAL_WRAPPER)
|
|
add_subdirectory(../src/wrappergen wrappergen)
|
|
endif()
|
|
|
|
if(BUILD_IFCGEOM)
|
|
# CGAL::CGAL target already has dependencies resolved.
|
|
if(WITH_CGAL AND CGAL_DIR)
|
|
set(CGAL_LIBRARIES CGAL::CGAL)
|
|
message(STATUS "Using found CGAL package at '${CGAL_DIR}'")
|
|
elseif(WITH_CGAL AND NOT CGAL_DIR)
|
|
find_library(libGMP NAMES gmp mpir PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
find_library(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH)
|
|
if(NOT libGMP)
|
|
message(FATAL_ERROR "Unable to find GMP library files, aborting")
|
|
endif()
|
|
if(NOT libMPFR)
|
|
message(FATAL_ERROR "Unable to find MPFR library files, aborting")
|
|
endif()
|
|
|
|
list(APPEND CGAL_LIBRARIES "${libMPFR}")
|
|
list(APPEND CGAL_LIBRARIES "${libGMP}")
|
|
endif()
|
|
|
|
add_subdirectory(../src/ifcgeom ifcgeom)
|
|
if(BUILD_IFCOPENSHELL_GEOMETRY_TESTS)
|
|
add_subdirectory(../src/ifcgeom/tests ifcgeom/tests)
|
|
endif()
|
|
elseif(BUILD_IFCOPENSHELL_GEOMETRY_TESTS)
|
|
message(FATAL_ERROR "BUILD_IFCOPENSHELL_GEOMETRY_TESTS requires BUILD_IFCGEOM=ON.")
|
|
endif(BUILD_IFCGEOM)
|
|
|
|
if(BUILD_CONVERT OR BUILD_IFCPYTHON OR BUILD_BONSAIVIEWER)
|
|
add_subdirectory(../src/serializers serializers)
|
|
endif(BUILD_CONVERT OR BUILD_IFCPYTHON OR BUILD_BONSAIVIEWER)
|
|
|
|
if(BUILD_CONVERT)
|
|
add_subdirectory(../src/ifcconvert ifcconvert)
|
|
endif(BUILD_CONVERT)
|
|
|
|
# IfcGeomServer
|
|
if(BUILD_GEOMSERVER)
|
|
add_subdirectory(../src/ifcgeomserver ifcgeomserver)
|
|
endif(BUILD_GEOMSERVER)
|
|
|
|
if(ADD_COMMIT_SHA)
|
|
find_package(Git)
|
|
|
|
if(NOT GIT_FOUND)
|
|
message(FATAL_ERROR "Failed to find Git for ADD_COMMIT_SHA option.")
|
|
endif()
|
|
|
|
if(GIT_FOUND)
|
|
if (VERSION_OVERRIDE)
|
|
set (git_branch ${RELEASE_VERSION})
|
|
else()
|
|
message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}")
|
|
execute_process(
|
|
COMMAND ${GIT_EXECUTABLE} branch -a --contains HEAD
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
OUTPUT_VARIABLE git_branches
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
)
|
|
string(REPLACE "\n" ";" git_branch_list "${git_branches}")
|
|
|
|
foreach(git_branch_candidate IN ITEMS ${git_branch_list})
|
|
string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}")
|
|
string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2)
|
|
if(NOT git_branch_candidate_2 MATCHES "^HEAD$")
|
|
string(REPLACE "/" ";" git_branch_candidate_2_list "${git_branch_candidate_2}")
|
|
list(GET git_branch_candidate_2_list -1 git_branch)
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
execute_process(
|
|
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
OUTPUT_VARIABLE git_sha
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
)
|
|
|
|
message(STATUS "IfcOpenShell branch: \"${git_branch}\"")
|
|
message(STATUS "IfcOpenShell commit: \"${git_sha}\"")
|
|
|
|
if ("${git_branch}" STREQUAL "" OR "${git_sha}" STREQUAL "")
|
|
message(FATAL_ERROR "Unable to determine commit sha and/or branch")
|
|
endif()
|
|
|
|
target_compile_definitions(IfcParse PRIVATE
|
|
-DIFCOPENSHELL_BRANCH=${git_branch}
|
|
-DIFCOPENSHELL_COMMIT=${git_sha}
|
|
)
|
|
endif()
|
|
endif(ADD_COMMIT_SHA)
|
|
|
|
# Always expose the release version (from the VERSION file) to buildinfo.cpp so
|
|
# that a build without commit-sha info reports the correct version instead of a
|
|
# stale hardcoded fallback. See #8164.
|
|
target_compile_definitions(IfcParse PRIVATE IFCOPENSHELL_VERSION_STRING=${RELEASE_VERSION})
|
|
|
|
if(MSVC)
|
|
# @todo still needs to be understood better, but the cgal and cgal-simple kernel cause multiply defined boost lambda placeholders _1 ... _3
|
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE")
|
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /FORCE:MULTIPLE")
|
|
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /FORCE:MULTIPLE")
|
|
endif()
|
|
|
|
# Documentation
|
|
if(BUILD_DOCUMENTATION)
|
|
set(CMAKE_MODULE_PATH "../docs/cmake")
|
|
add_subdirectory(../docs docs)
|
|
endif()
|
|
|
|
if(BUILD_EXAMPLES)
|
|
add_subdirectory(../src/examples examples)
|
|
endif()
|
|
|
|
if(BUILD_IFCMAX)
|
|
add_subdirectory(../src/ifcmax ifcmax)
|
|
endif()
|
|
|
|
if(BUILD_IFCPYTHON AND WITH_CGAL)
|
|
add_subdirectory(../src/svgfill svgfill)
|
|
endif()
|
|
|
|
if(BUILD_IFCPYTHON)
|
|
add_subdirectory(../src/ifcwrap ifcwrap)
|
|
endif()
|
|
|
|
if(BUILD_QTVIEWER)
|
|
add_subdirectory(../src/qtviewer qtviewer)
|
|
endif()
|
|
|
|
if(BUILD_IFCMODEL_UI)
|
|
add_subdirectory(../src/ifcmodel-ui ifcmodel-ui)
|
|
endif()
|
|
|
|
if(BUILD_IFCGEOM)
|
|
# install(FILES ${IFCGEOM_H_FILES}
|
|
# DESTINATION ${INCLUDEDIR}/ifcgeom
|
|
# )
|
|
|
|
install(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
|
DESTINATION ${INCLUDEDIR}/ifcgeom
|
|
)
|
|
|
|
file(GLOB SERIALIZATION_H_FILES ../src/ifcgeom/serialization/*.h)
|
|
install(FILES ${SERIALIZATION_H_FILES}
|
|
DESTINATION ${INCLUDEDIR}/ifcgeom/serialization
|
|
)
|
|
|
|
foreach(kernel ${GEOMETRY_KERNELS})
|
|
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/${kernel}/*.h)
|
|
install(FILES ${IFCGEOM_H_FILES}
|
|
DESTINATION ${INCLUDEDIR}/ifcgeom/kernels/${kernel}
|
|
)
|
|
endforeach()
|
|
|
|
install(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} ${kernel_libraries} IfcGeom)
|
|
endif(BUILD_IFCGEOM)
|
|
if(BUILD_BONSAIVIEWER)
|
|
# IfcViewer is the unified scene + render lib since the wgpu/ifcviewer
|
|
# merge — wgpu-native is fetched inside its CMakeLists.txt.
|
|
add_subdirectory(../src/ifcviewer ifcviewer)
|
|
if(BUILD_BONSAIVIEWER_WGPU)
|
|
add_subdirectory(../src/ifcviewer-minimal ifcviewer-minimal)
|
|
endif()
|
|
add_subdirectory(../src/bonsaiviewer bonsaiviewer)
|
|
endif()
|
|
|
|
if(BUILD_FUZZERS)
|
|
add_subdirectory(../src/ifcfuzz ifcfuzz)
|
|
endif()
|
|
|
|
# Cmake uninstall target
|
|
if(NOT TARGET uninstall)
|
|
configure_file(
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
|
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
|
IMMEDIATE @ONLY)
|
|
|
|
add_custom_target(uninstall
|
|
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
|
endif()
|
|
|
|
# Packaging
|
|
list(APPEND CPACK_SOURCE_IGNORE_FILES
|
|
"/\\\\.git"
|
|
"/build/"
|
|
"/.pytest_cache/"
|
|
"/__pycache__/"
|
|
)
|
|
set(CPACK_SOURCE_INSTALLED_DIRECTORIES "${CMAKE_SOURCE_DIR}/..;/")
|
|
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}")
|
|
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}")
|
|
SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}")
|
|
set(CPACK_PACKAGE_DIRECTORY "${PROJECT_BINARY_DIR}/assets")
|
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IfcOpenShell")
|
|
set(CPACK_PACKAGE_DESCRIPTION "IfcOpenShell.")
|
|
set(CPACK_PACKAGE_VENDOR "Cemosis")
|
|
set(CPACK_PACKAGE_CONTACT "Christophe Prud'homme <christophe.prudhomme@cemosis.fr>")
|
|
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
|
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
|
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
|
|
|
|
set(CPACK_GENERATOR "TGZ;DEB")
|
|
set(CPACK_SOURCE_GENERATOR "TGZ")
|
|
|
|
foreach(COMPONENT IN ITEMS ${BOOST_COMPONENTS})
|
|
string(REPLACE "_" "-" COMP ${COMPONENT})
|
|
set(BOOST_DEPS "${BOOST_DEPS}, libboost-${COMP}-dev")
|
|
endforeach(COMPONENT)
|
|
|
|
set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}")
|
|
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_CONTACT}")
|
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python3, libxml2, libocct-foundation-dev, libocct-modeling-algorithms-dev, libocct-modeling-data-dev, libocct-ocaf-dev, libocct-visualization-dev, libocct-data-exchange-dev, libpython3-dev, python3-pytest ${BOOST_DEPS}")
|
|
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
|
|
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}")
|
|
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
|
set(CPACK_DEBIAN_PACKAGE_SECTION "science")
|
|
set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}")
|
|
set(CPACK_DEBIAN_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
|
|
# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst")
|
|
|
|
include(CPack)
|