From 4122759f1a3c879b077c3dfa4606efc67899452d Mon Sep 17 00:00:00 2001 From: aothms Date: Mon, 15 Feb 2016 16:59:47 +0100 Subject: [PATCH 1/4] Add option to compile (external) schema by cmake --- cmake/CMakeLists.txt | 80 ++++++++++++++++++++++----- src/ifcexpressparser/bootstrap.py | 2 + src/ifcexpressparser/documentation.py | 11 +++- win/run-cmake.bat | 2 + 4 files changed, 79 insertions(+), 16 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a232058a13..b55c046949 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -47,6 +47,7 @@ UNIFY_ENVVARS_AND_CACHE(ICU_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) # Find Boost IF(MSVC) @@ -274,25 +275,78 @@ if(NOT WIN32) INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} /usr/inc /usr/local/inc /usr/local/include/oce) endif() -IF(USE_IFC4) - ADD_DEFINITIONS(-DUSE_IFC4) - SET(IFC_RELEASE_NOT_USED "2x3") -ELSE() - ADD_DEFINITIONS(-DUSE_IFC2x3) # TODO Make all caps? i.e. USE_IFC2X3 - SET(IFC_RELEASE_NOT_USED "4") -ENDIF() +function(files_for_ifc_version IFC_VERSION RESULT_NAME) + set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse) + set(${RESULT_NAME} + ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h + ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h + ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.h + ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp + ${IFC_PARSE_DIR}/Ifc${IFC_VERSION}-latebound.cpp + PARENT_SCOPE + ) +endfunction() + +if(COMPILE_SCHEMA) + set(IFC_RELEASE_NOT_USED "2x3" "4") + + if(PYTHON_EXECUTABLE) + set(PYTHON_EXECUTABLE_USED ${PYTHON_EXECUTABLE}) + else() + set(PYTHON_EXECUTABLE_USED "python") + endif() + + # Install pyparsing if necessary + execute_process(COMMAND ${PYTHON_EXECUTABLE_USED} -m pip "list" OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) + string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND) + if ("${PYPARSING_FOUND}" STREQUAL "-1") + message(STATUS "Installing pyparsing") + execute_process(COMMAND ${PYTHON_EXECUTABLE_USED} -m pip "install" --user pyparsing) + 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_USED} bootstrap.py express.bnf + WORKING_DIRECTORY ../src/ifcexpressparser + OUTPUT_FILE express_parser.py) + + # Generate code + execute_process(COMMAND ${PYTHON_EXECUTABLE_USED} ../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 + if(${COMPILED_SCHEMA_NAME} STREQUAL "IFC2X3") + list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3") + elseif(${COMPILED_SCHEMA_NAME} STREQUAL "IFC4") + list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4") + endif() +else() + if(USE_IFC4) + add_definitions(-DUSE_IFC4) + set(IFC_RELEASE_NOT_USED "2x3") + else() + add_definitions(-DUSE_IFC2x3) # TODO Make all caps? i.e. USE_IFC2X3 + set(IFC_RELEASE_NOT_USED "4") + endif() +endif() # IfcParse file(GLOB CPP_FILES ../src/ifcparse/*.cpp) file(GLOB H_FILES ../src/ifcparse/*.h) set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) -# Remove sources specific to an IFC release we are not using -list(REMOVE_ITEM SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse/Ifc${IFC_RELEASE_NOT_USED}.h) -list(REMOVE_ITEM SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse/Ifc${IFC_RELEASE_NOT_USED}enum.h) -list(REMOVE_ITEM SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse/Ifc${IFC_RELEASE_NOT_USED}-latebound.h) -list(REMOVE_ITEM SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse/Ifc${IFC_RELEASE_NOT_USED}.cpp) -list(REMOVE_ITEM SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse/Ifc${IFC_RELEASE_NOT_USED}-latebound.cpp) + +foreach(IFC_RELEASE ${IFC_RELEASE_NOT_USED}) + files_for_ifc_version(${IFC_RELEASE} SOURCE_FILES_NOT_USED) + foreach(SOURCE_FILE ${SOURCE_FILES_NOT_USED}) + list(REMOVE_ITEM SOURCE_FILES ${SOURCE_FILE}) + endforeach() +endforeach() + ADD_LIBRARY(IfcParse STATIC ${SOURCE_FILES}) + IF(UNICODE_SUPPORT) TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES}) ENDIF() diff --git a/src/ifcexpressparser/bootstrap.py b/src/ifcexpressparser/bootstrap.py index bb9e4a58e6..d59fe55048 100644 --- a/src/ifcexpressparser/bootstrap.py +++ b/src/ifcexpressparser/bootstrap.py @@ -184,4 +184,6 @@ enum_header.EnumHeader(mapping).emit() implementation.Implementation(mapping).emit() latebound_header.LateBoundHeader(mapping).emit() latebound_implementation.LateBoundImplementation(mapping).emit() + +sys.stdout.write(schema.name) """%('\n'.join(statements))) diff --git a/src/ifcexpressparser/documentation.py b/src/ifcexpressparser/documentation.py index e83bc132a8..ef8bde5a69 100644 --- a/src/ifcexpressparser/documentation.py +++ b/src/ifcexpressparser/documentation.py @@ -27,11 +27,15 @@ # # ############################################################################### -import re,csv +import re +import os import csv + try: from html.entities import entitydefs except: from htmlentitydefs import entitydefs +make_absolute = lambda fn: os.path.join(os.path.dirname(os.path.realpath(__file__)), fn) + name_to_oid = {} oid_to_desc = {} oid_to_name = {} @@ -39,6 +43,7 @@ oid_to_pid = {} regices = list(zip([re.compile(s,re.M) for s in [r'<[\w\n=" \-/\.;_\t:%#,\?\(\)]+>',r'(\n[\t ]*){2,}',r'^[\t ]+']],['','\n\n',' '])) definition_files = ['DocEntity.csv', 'DocEnumeration.csv', 'DocDefined.csv', 'DocSelect.csv'] +definition_files = map(make_absolute, definition_files) for fn in definition_files: with open(fn) as f: for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'): @@ -46,11 +51,11 @@ for fn in definition_files: oid_to_name[oid] = name oid_to_desc[oid] = desc -with open('DocEntityAttributes.csv') as f: +with open(make_absolute('DocEntityAttributes.csv')) as f: for pid, x, oid in csv.reader(f, delimiter=';', quotechar='"'): oid_to_pid[oid] = pid -with open('DocAttribute.csv') as f: +with open(make_absolute('DocAttribute.csv')) as f: for oid, name, desc in csv.reader(f, delimiter=';', quotechar='"'): pid = oid_to_pid[oid] pname = oid_to_name[pid] diff --git a/win/run-cmake.bat b/win/run-cmake.bat index d9fb548743..c714b72484 100644 --- a/win/run-cmake.bat +++ b/win/run-cmake.bat @@ -56,6 +56,7 @@ if not defined PY_VER_MAJOR_MINOR set PY_VER_MAJOR_MINOR=34 if not defined PYTHONPATH set PYTHONPATH=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% set PYTHON_INCLUDE_DIR=%PYTHONPATH%\include set PYTHON_LIBRARY=%PYTHONPATH%\libs\python%PY_VER_MAJOR_MINOR%.lib +set PYTHON_EXECUTABLE=%PYTHONPATH%\python.exe set SWIG_DIR=%INSTALL_DIR%\swigwin set PATH=%PATH%;%SWIG_DIR%;%PYTHONPATH% :: TODO 3ds Max SDK? @@ -77,6 +78,7 @@ echo OPENCOLLADA_LIBRARY_DIR = %OPENCOLLADA_LIBRARY_DIR% echo PYTHONPATH = %PYTHONPATH% echo PYTHON_INCLUDE_DIR = %PYTHON_INCLUDE_DIR% echo PYTHON_LIBRARY = %PYTHON_LIBRARY% +echo PYTHON_EXECUTABLE = %PYTHON_EXECUTABLE% echo SWIG_DIR = %SWIG_DIR% echo. echo CMAKE_INSTALL_PREFIX = %CMAKE_INSTALL_PREFIX% From a6094f50b9023549266e8eb6b40a14d99ec41a1d Mon Sep 17 00:00:00 2001 From: aothms Date: Wed, 17 Feb 2016 12:03:38 +0100 Subject: [PATCH 2/4] Let CMake find python interpreter for schema compilation and installation dir Remove unused compiled schema in cpp installation target --- cmake/CMakeLists.txt | 60 ++++++++++++++++++-------------------- src/ifcwrap/CMakeLists.txt | 40 +++++++++++++++---------- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b55c046949..0bace9a278 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -288,32 +288,32 @@ function(files_for_ifc_version IFC_VERSION RESULT_NAME) endfunction() if(COMPILE_SCHEMA) + 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 "2x3" "4") - if(PYTHON_EXECUTABLE) - set(PYTHON_EXECUTABLE_USED ${PYTHON_EXECUTABLE}) - else() - set(PYTHON_EXECUTABLE_USED "python") - endif() - # Install pyparsing if necessary - execute_process(COMMAND ${PYTHON_EXECUTABLE_USED} -m pip "list" OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "list" OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) string(FIND "${PYTHON_PACKAGE_LIST}" pyparsing PYPARSING_FOUND) if ("${PYPARSING_FOUND}" STREQUAL "-1") message(STATUS "Installing pyparsing") - execute_process(COMMAND ${PYTHON_EXECUTABLE_USED} -m pip "install" --user pyparsing) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing) 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_USED} bootstrap.py express.bnf + execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf WORKING_DIRECTORY ../src/ifcexpressparser OUTPUT_FILE express_parser.py) # Generate code - execute_process(COMMAND ${PYTHON_EXECUTABLE_USED} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA} + execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA} WORKING_DIRECTORY ../src/ifcparse OUTPUT_VARIABLE COMPILED_SCHEMA_NAME) @@ -334,28 +334,31 @@ else() endif() # IfcParse -file(GLOB CPP_FILES ../src/ifcparse/*.cpp) -file(GLOB H_FILES ../src/ifcparse/*.h) -set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) +file(GLOB IFCPARSE_H_FILES ../src/ifcparse/*.h) +file(GLOB IFCPARSE_CPP_FILES ../src/ifcparse/*.cpp) foreach(IFC_RELEASE ${IFC_RELEASE_NOT_USED}) files_for_ifc_version(${IFC_RELEASE} SOURCE_FILES_NOT_USED) foreach(SOURCE_FILE ${SOURCE_FILES_NOT_USED}) - list(REMOVE_ITEM SOURCE_FILES ${SOURCE_FILE}) + list(REMOVE_ITEM IFCPARSE_CPP_FILES ${SOURCE_FILE}) + list(REMOVE_ITEM IFCPARSE_H_FILES ${SOURCE_FILE}) endforeach() endforeach() -ADD_LIBRARY(IfcParse STATIC ${SOURCE_FILES}) +set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES}) + +ADD_LIBRARY(IfcParse STATIC ${IFCPARSE_FILES}) IF(UNICODE_SUPPORT) TARGET_LINK_LIBRARIES(IfcParse ${ICU_LIBRARIES}) ENDIF() # IfcGeom -file(GLOB CPP_FILES ../src/ifcgeom/*.cpp) -file(GLOB H_FILES ../src/ifcgeom/*.h) -set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) -ADD_LIBRARY(IfcGeom STATIC ${SOURCE_FILES}) +file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h) +file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp) + +set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) +ADD_LIBRARY(IfcGeom STATIC ${IFCGEOM_FILES}) TARGET_LINK_LIBRARIES(IfcGeom IfcParse) @@ -366,10 +369,10 @@ if(NOT WIN32) LINK_DIRECTORIES(${LINK_DIRECTORIES} /usr/lib /usr/lib64 /usr/local/lib /usr/local/lib64) endif() -file(GLOB CPP_FILES ../src/ifcconvert/*.cpp) -file(GLOB H_FILES ../src/ifcconvert/*.h) -set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) -ADD_EXECUTABLE(IfcConvert ${SOURCE_FILES}) +file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp) +file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h) +set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES}) +ADD_EXECUTABLE(IfcConvert ${IFCCONVERT_FILES}) # Make sure cross-referenced symbols between static OCC libraries get # resolved. Also add thread and rt libraries. @@ -397,15 +400,8 @@ IF(BUILD_EXAMPLES) ADD_SUBDIRECTORY(../src/examples examples) ENDIF() -# TODO QtViewer is deprecated ATM as it uses the 0.4 API -# IF(BUILD_QTVIEWER) - # ADD_SUBDIRECTORY(../src/qtviewer qtviewer) -# ENDIF() - # CMake installation targets -FILE(GLOB include_files_geom ../src/ifcgeom/*.h) -FILE(GLOB include_files_parse ../src/ifcparse/*.h) -INSTALL(FILES ${include_files_geom} DESTINATION include/ifcgeom) -INSTALL(FILES ${include_files_parse} DESTINATION include/ifcparse) +INSTALL(FILES ${IFCPARSE_H_FILES} DESTINATION include/ifcparse) +INSTALL(FILES ${IFCGEOM_H_FILES} DESTINATION include/ifcgeom) INSTALL(TARGETS IfcConvert IfcGeomServer DESTINATION bin) INSTALL(TARGETS IfcParse IfcGeom DESTINATION lib) diff --git a/src/ifcwrap/CMakeLists.txt b/src/ifcwrap/CMakeLists.txt index a431cb0c00..ba2b6a0c59 100644 --- a/src/ifcwrap/CMakeLists.txt +++ b/src/ifcwrap/CMakeLists.txt @@ -54,21 +54,29 @@ SET_SOURCE_FILES_PROPERTIES(IfcPython.i PROPERTIES CPLUSPLUS ON) SWIG_ADD_MODULE(ifcopenshell_wrapper python IfcPython.i) SWIG_LINK_LIBRARIES(ifcopenshell_wrapper IfcParse IfcGeom ${PYTHON_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${ICU_LIBRARIES}) -# To install IfcPython let's get the site-packages dir from python -EXECUTE_PROCESS(COMMAND - python -c "import sys; from distutils.sysconfig import get_python_lib; sys.stdout.write(get_python_lib())" - OUTPUT_VARIABLE python_package_dir) +# Try to find the Python interpreter to get the site-packages +# directory in which the wrapper can be installed. +FIND_PACKAGE(PythonInterp) +IF(PYTHONINTERP_FOUND) + EXECUTE_PROCESS( + COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils.sysconfig import get_python_lib; sys.stdout.write(get_python_lib())" + OUTPUT_VARIABLE python_package_dir + ) -IF("${python_package_dir}" STREQUAL "") - MESSAGE(FATAL_ERROR "Python executable not in PATH, aborting") + IF("${python_package_dir}" STREQUAL "") + MESSAGE(WARNING "Unable to locate Python site-package directory, unable to install the Python wrapper") + ELSE() + INSTALL(FILES + "${CMAKE_BINARY_DIR}/ifcwrap/ifcopenshell_wrapper.py" + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/__init__.py" + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/guid.py" + DESTINATION "${python_package_dir}/ifcopenshell") + INSTALL(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/geom/__init__.py" + "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/geom/occ_utils.py" + DESTINATION "${python_package_dir}/ifcopenshell/geom") + INSTALL(TARGETS _ifcopenshell_wrapper DESTINATION "${python_package_dir}/ifcopenshell") + ENDIF() +ELSE() + MESSAGE(WARNING "No Python interpreter found, unable to install the Python wrapper") ENDIF() - -INSTALL(FILES - "${CMAKE_BINARY_DIR}/ifcwrap/ifcopenshell_wrapper.py" - "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/__init__.py" - "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/guid.py" - DESTINATION "${python_package_dir}/ifcopenshell") -INSTALL(FILES - "${CMAKE_CURRENT_SOURCE_DIR}/../ifcopenshell-python/ifcopenshell/geom/__init__.py" - DESTINATION "${python_package_dir}/ifcopenshell/geom") -INSTALL(TARGETS _ifcopenshell_wrapper DESTINATION "${python_package_dir}/ifcopenshell") From da0af775700c6218f29a03521e6f22a696612590 Mon Sep 17 00:00:00 2001 From: aothms Date: Thu, 18 Feb 2016 13:17:15 +0100 Subject: [PATCH 3/4] Compatibility for older versions of cmake, python, open cascade, boost --- cmake/CMakeLists.txt | 31 +++++++++++++---- src/ifcexpressparser/codegen.py | 34 +++++++++++++++++++ src/ifcexpressparser/enum_header.py | 11 +++--- src/ifcexpressparser/header.py | 12 +++---- src/ifcexpressparser/implementation.py | 12 +++---- src/ifcexpressparser/latebound_header.py | 11 +++--- .../latebound_implementation.py | 12 +++---- src/ifcexpressparser/mapping.py | 6 ++-- src/ifcexpressparser/schema.py | 13 ++++--- src/ifcgeom/IfcGeomFaces.cpp | 8 +++++ src/ifcgeom/IfcGeomFunctions.cpp | 8 ++++- src/ifcgeom/IfcGeomShapes.cpp | 6 ++++ src/ifcparse/IfcGlobalId.cpp | 10 ++++++ 13 files changed, 133 insertions(+), 41 deletions(-) create mode 100644 src/ifcexpressparser/codegen.py diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0bace9a278..71963665ca 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -17,7 +17,7 @@ # # ################################################################################ -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 2.8.5) project (IfcOpenShell) @@ -297,11 +297,23 @@ if(COMPILE_SCHEMA) set(IFC_RELEASE_NOT_USED "2x3" "4") # Install pyparsing if necessary - execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "list" OUTPUT_VARIABLE PYTHON_PACKAGE_LIST) + 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) + 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() @@ -310,7 +322,12 @@ if(COMPILE_SCHEMA) 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) + 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} @@ -318,10 +335,12 @@ if(COMPILE_SCHEMA) OUTPUT_VARIABLE COMPILED_SCHEMA_NAME) # Prevent the schema that had just been compiled from being excluded - if(${COMPILED_SCHEMA_NAME} STREQUAL "IFC2X3") + if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3") list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3") - elseif(${COMPILED_SCHEMA_NAME} STREQUAL "IFC4") + add_definitions(-DUSE_IFC2x3) + elseif("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC4") list(REMOVE_ITEM IFC_RELEASE_NOT_USED "4") + add_definitions(-DUSE_IFC4) endif() else() if(USE_IFC4) diff --git a/src/ifcexpressparser/codegen.py b/src/ifcexpressparser/codegen.py new file mode 100644 index 0000000000..6370b3dc87 --- /dev/null +++ b/src/ifcexpressparser/codegen.py @@ -0,0 +1,34 @@ +############################################################################### +# # +# 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 . # +# # +############################################################################### + +class Base(object): + """ + A base class for all code generation classes. Currently only working around + some python 2/3 incompatibilities in terms of unicode file handling. + """ + def emit(self): + import platform + if tuple(map(int, platform.python_version_tuple())) < (2, 8): + from io import open as unicode_open + else: + unicode_open = open + unicode = lambda x, *args, **kwargs: x + f = unicode_open(self.file_name, 'w', encoding='utf-8') + f.write(unicode(repr(self), encoding='utf-8', errors='ignore')) + f.close() diff --git a/src/ifcexpressparser/enum_header.py b/src/ifcexpressparser/enum_header.py index 96993ec13f..eb382a3e7a 100644 --- a/src/ifcexpressparser/enum_header.py +++ b/src/ifcexpressparser/enum_header.py @@ -18,8 +18,9 @@ ############################################################################### import templates +import codegen -class EnumHeader: +class EnumHeader(codegen.Base): def __init__(self, mapping): enumerable_types = sorted(set([name for name, type in mapping.schema.types.items()] + [name for name, type in mapping.schema.entities.items()])) @@ -30,9 +31,9 @@ class EnumHeader: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%senum.h'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%senum.h'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() diff --git a/src/ifcexpressparser/header.py b/src/ifcexpressparser/header.py index 51f4a89242..449506bc0f 100644 --- a/src/ifcexpressparser/header.py +++ b/src/ifcexpressparser/header.py @@ -17,10 +17,11 @@ # # ############################################################################### +import codegen import templates import documentation -class Header: +class Header(codegen.Base): def __init__(self, mapping): declarations = [] @@ -123,10 +124,9 @@ class Header: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s.h'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s.h'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() - diff --git a/src/ifcexpressparser/implementation.py b/src/ifcexpressparser/implementation.py index f4e0759da3..f26581cf0e 100644 --- a/src/ifcexpressparser/implementation.py +++ b/src/ifcexpressparser/implementation.py @@ -17,9 +17,10 @@ # # ############################################################################### +import codegen import templates -class Implementation: +class Implementation(codegen.Base): def __init__(self, mapping): enumeration_functions = [] entity_implementations = [] @@ -230,10 +231,9 @@ class Implementation: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s.cpp'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s.cpp'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() - diff --git a/src/ifcexpressparser/latebound_header.py b/src/ifcexpressparser/latebound_header.py index bf2db78f3e..251a288073 100644 --- a/src/ifcexpressparser/latebound_header.py +++ b/src/ifcexpressparser/latebound_header.py @@ -17,9 +17,10 @@ # # ############################################################################### +import codegen import templates -class LateBoundHeader: +class LateBoundHeader(codegen.Base): def __init__(self, mapping): self.str = templates.lb_header % { 'schema_name_upper' : mapping.schema.name.upper(), @@ -27,9 +28,9 @@ class LateBoundHeader: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s-latebound.h'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s-latebound.h'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() diff --git a/src/ifcexpressparser/latebound_implementation.py b/src/ifcexpressparser/latebound_implementation.py index fe9e600ecd..1303d000ff 100644 --- a/src/ifcexpressparser/latebound_implementation.py +++ b/src/ifcexpressparser/latebound_implementation.py @@ -17,9 +17,10 @@ # # ############################################################################### +import codegen import templates -class LateBoundImplementation: +class LateBoundImplementation(codegen.Base): def __init__(self, mapping): schema_name = mapping.schema.name.capitalize() @@ -110,10 +111,9 @@ class LateBoundImplementation: } self.schema_name = mapping.schema.name.capitalize() + + self.file_name = '%s-latebound.cpp'%self.schema_name + + def __repr__(self): return self.str - def emit(self): - f = open('%s-latebound.cpp'%self.schema_name, 'w', encoding='utf-8') - f.write(str(self)) - f.close() - diff --git a/src/ifcexpressparser/mapping.py b/src/ifcexpressparser/mapping.py index ee536697fd..5b9721e191 100644 --- a/src/ifcexpressparser/mapping.py +++ b/src/ifcexpressparser/mapping.py @@ -17,6 +17,8 @@ # # ############################################################################### +from __future__ import print_function + import sys import nodes import templates @@ -33,11 +35,11 @@ class Mapping: 'binary' : 'boost::dynamic_bitset<>' } - supported_argument_types = { + supported_argument_types = set([ 'INT', 'BOOL', 'DOUBLE', 'STRING', 'BINARY', 'ENUMERATION', 'ENTITY_INSTANCE', 'AGGREGATE_OF_INT', 'AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_STRING', 'AGGREGATE_OF_BINARY', 'AGGREGATE_OF_ENTITY_INSTANCE', 'AGGREGATE_OF_AGGREGATE_OF_INT', 'AGGREGATE_OF_AGGREGATE_OF_DOUBLE', 'AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE', - } + ]) def __init__(self, schema): self.schema = schema diff --git a/src/ifcexpressparser/schema.py b/src/ifcexpressparser/schema.py index 74d62bfacb..18335f3cdf 100644 --- a/src/ifcexpressparser/schema.py +++ b/src/ifcexpressparser/schema.py @@ -18,8 +18,13 @@ ############################################################################### import nodes +import platform import collections +if tuple(map(int, platform.python_version_tuple())) < (2, 7): + import ordereddict + collections.OrderedDict = ordereddict.OrderedDict + class Schema: def is_enumeration(self, v): return str(v) in self.enumerations @@ -34,12 +39,12 @@ class Schema: def __init__(self, parsetree): self.name = parsetree[1] - sort = lambda d: collections.OrderedDict(sorted(d.items())) + sort = lambda d: collections.OrderedDict(sorted(d)) - self.types = sort({t.name:t for t in parsetree if isinstance(t, nodes.TypeDeclaration)}) - self.entities = sort({t.name:t for t in parsetree if isinstance(t, nodes.EntityDeclaration)}) + self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)]) + self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)]) - of_type = lambda *types: sort({a: b.type.type for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)}) + of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)]) self.enumerations = of_type(nodes.EnumerationType) self.selects = of_type(nodes.SelectType) diff --git a/src/ifcgeom/IfcGeomFaces.cpp b/src/ifcgeom/IfcGeomFaces.cpp index 6d83f90609..91753fc137 100644 --- a/src/ifcgeom/IfcGeomFaces.cpp +++ b/src/ifcgeom/IfcGeomFaces.cpp @@ -893,7 +893,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPlane* l, TopoDS_Shape& face) gp_Pln pln; convert(l, pln); Handle_Geom_Surface surf = new Geom_Plane(pln); +#if OCC_VERSION_HEX < 0x60502 + face = BRepBuilderAPI_MakeFace(surf); +#else face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION)); +#endif return true; } @@ -942,7 +946,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBSplineSurfaceWithKnots* l, To } Handle_Geom_Surface surf = new Geom_BSplineSurface(Poles, UKnots, VKnots, UMults, VMults, UDegree, VDegree); +#if OCC_VERSION_HEX < 0x60502 + face = BRepBuilderAPI_MakeFace(surf); +#else face = BRepBuilderAPI_MakeFace(surf, getValue(GV_PRECISION)); +#endif return true; } diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 1ed8ee1627..14dd47230f 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -63,6 +63,9 @@ #include #include #include +#include + +#include #include #include @@ -95,7 +98,6 @@ #include #include -#include #include #include #include @@ -106,7 +108,11 @@ #include "../ifcgeom/IfcGeom.h" #if OCC_VERSION_HEX < 0x60900 +#ifdef _MSC_VER #pragma message("warning: You are linking against Open CASCADE version " OCC_VERSION_COMPLETE ". Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade.") +#else +#warning "You are linking against linking against an older version of Open CASCADE. Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade." +#endif #endif bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index 0e1b0747cb..008ce6a9e8 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -65,6 +65,8 @@ #include #include #include +#include + #include #include @@ -859,7 +861,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_ gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); +#if OCC_VERSION_HEX < 0x60502 + face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf); +#else face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf); +#endif return true; } diff --git a/src/ifcparse/IfcGlobalId.cpp b/src/ifcparse/IfcGlobalId.cpp index f6ab34b48c..e70189071f 100644 --- a/src/ifcparse/IfcGlobalId.cpp +++ b/src/ifcparse/IfcGlobalId.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "../ifcparse/IfcGlobalId.h" #include "../ifcparse/IfcException.h" @@ -87,7 +89,11 @@ IfcParse::IfcGlobalId::IfcGlobalId() { std::vector v(uuid_data.size()); std::copy(uuid_data.begin(), uuid_data.end(), v.begin()); string_data = compress(&v[0]); +#if BOOST_VERSION < 104400 + formatted_string = boost::lexical_cast(uuid_data); +#else formatted_string = boost::uuids::to_string(uuid_data); +#endif #ifndef NDEBUG std::vector test_vector; @@ -106,7 +112,11 @@ IfcParse::IfcGlobalId::IfcGlobalId(const std::string& s) std::vector v; expand(string_data, v); std::copy(v.begin(), v.end(), uuid_data.begin()); +#if BOOST_VERSION < 104400 + formatted_string = boost::lexical_cast(uuid_data); +#else formatted_string = boost::uuids::to_string(uuid_data); +#endif #ifndef NDEBUG const std::string test_string = compress(&uuid_data.data[0]); From 10bec3eee0f62d435599127326a6748a5538e613 Mon Sep 17 00:00:00 2001 From: aothms Date: Thu, 18 Feb 2016 14:57:57 +0100 Subject: [PATCH 4/4] Replace PYTHONPATH with PYTHONHOME --- win/build-deps.cmd | 8 ++++---- win/readme.md | 6 +++--- win/run-cmake.bat | 12 ++++++------ win/set-python-to-path.bat | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/win/build-deps.cmd b/win/build-deps.cmd index b145347bf9..d7d8b44b35 100644 --- a/win/build-deps.cmd +++ b/win/build-deps.cmd @@ -253,7 +253,7 @@ set PYTHON_VERSION=3.4.3 IF "%IFCOS_USE_PYTHON2%"=="TRUE" set PYTHON_VERSION=2.7.10 set PY_VER_MAJOR_MINOR=%PYTHON_VERSION:~0,3% set PY_VER_MAJOR_MINOR=%PY_VER_MAJOR_MINOR:.=% -set PYTHONPATH=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% +set PYTHONHOME=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% set DEPENDENCY_NAME=Python %PYTHON_VERSION% set DEPENDENCY_DIR=N/A @@ -265,7 +265,7 @@ set PYTHON_INSTALLER=python-%PYTHON_VERSION%%PYTHON_AMD64_POSTFIX%.msi IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( REM Store Python versions to BuildDepsCache.txt for run-cmake.bat echo PY_VER_MAJOR_MINOR=%PY_VER_MAJOR_MINOR%>"%~dp0\BuildDepsCache-%TARGET_ARCH%.txt" - echo PYTHONPATH=%PYTHONPATH%>>"%~dp0\BuildDepsCache-%TARGET_ARCH%.txt" + echo PYTHONHOME=%PYTHONHOME%>>"%~dp0\BuildDepsCache-%TARGET_ARCH%.txt" cd "%DEPS_DIR%" call :DownloadFile https://www.python.org/ftp/python/%PYTHON_VERSION%/%PYTHON_INSTALLER% "%DEPS_DIR%" %PYTHON_INSTALLER% @@ -276,9 +276,9 @@ IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" ( msiexec /x %PYTHON_INSTALLER% /qn ) - IF NOT EXIST "%PYTHONPATH%". ( + IF NOT EXIST "%PYTHONHOME%". ( call cecho.cmd 0 13 "Installing %DEPENDENCY_NAME%. Please be patient, this will take a while." - msiexec /qn /i %PYTHON_INSTALLER% TARGETDIR="%PYTHONPATH%" + msiexec /qn /i %PYTHON_INSTALLER% TARGETDIR="%PYTHONHOME%" ) ELSE ( call cecho.cmd 0 13 "%DEPENDENCY_NAME% already installed. Skipping." ) diff --git a/win/readme.md b/win/readme.md index f91e3a7bae..dd85e652e0 100644 --- a/win/readme.md +++ b/win/readme.md @@ -40,7 +40,7 @@ After this, one can build the project using the `IfcOpenShell.sln` file in the b if wanted. Convenience batch files `build-ifcopenshell.cmd` and `install-ifcopenshell.cmd` can also be used. The batch files expect `%1` and `%2` in same fashion as above and possible extra parameters are passed for the `MSBuild` call. The project will be installed to `installed-vs-\` folder in the project's root folder and the required IfcOpenShell-Python -parts are deployed to the `\Lib\site-packages\` folder. +parts are deployed to the `\Lib\site-packages\` folder. **Note:** All of the dependencies are build as static libraries against the static run-time allowing the developer to effortlessly deploy standalone IFCOS binaries. @@ -58,7 +58,7 @@ Before building the dependencies, disable the script from installing Python: After bulding the dependencies, create BuildDepsCache file to `IfcOpenShell\win` which tells the used Python version and intallation directory: ``` > echo PY_VER_MAJOR_MINOR=35> BuildDepsCache-x64.txt -> echo PYTHONPATH=C:\Python3>> BuildDepsCache-x64.txt +> echo PYTHONHOME=C:\Python3>> BuildDepsCache-x64.txt ``` After this you should be able to run `run-cmake.bat` normally. If using 32-bit Python, the name of the file must be `BuildDepsCache-x86.txt`. @@ -80,7 +80,7 @@ Directory Structure | install-ifcopenshell.cmd - Builds IFCOS's INSTALL project | readme.md - This file | run-cmake.bat - Sets environment variables for the dependencies and runs CMake for IFCOS -| set-python-to-path.bat - Utility for setting PYTHONPATH (read from BuildDepsCache-.txt) to PATH +| set-python-to-path.bat - Utility for setting PYTHONHOME (read from BuildDepsCache-.txt) to PATH | vs-cfg.cmd - Utility file used by the build scripts +---sln - Contains the old Visual Studio solution and project files \---utils - Contains various utilities for the build scripts diff --git a/win/run-cmake.bat b/win/run-cmake.bat index c714b72484..1c2865d723 100644 --- a/win/run-cmake.bat +++ b/win/run-cmake.bat @@ -53,12 +53,12 @@ set OCC_LIBRARY_DIR=%INSTALL_DIR%\oce\Win%ARCH_BITS%\lib set OPENCOLLADA_INCLUDE_DIR=%INSTALL_DIR%\OpenCOLLADA\include\opencollada set OPENCOLLADA_LIBRARY_DIR=%INSTALL_DIR%\OpenCOLLADA\lib\opencollada if not defined PY_VER_MAJOR_MINOR set PY_VER_MAJOR_MINOR=34 -if not defined PYTHONPATH set PYTHONPATH=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% -set PYTHON_INCLUDE_DIR=%PYTHONPATH%\include -set PYTHON_LIBRARY=%PYTHONPATH%\libs\python%PY_VER_MAJOR_MINOR%.lib -set PYTHON_EXECUTABLE=%PYTHONPATH%\python.exe +if not defined PYTHONHOME set PYTHONHOME=%INSTALL_DIR%\Python%PY_VER_MAJOR_MINOR% +set PYTHON_INCLUDE_DIR=%PYTHONHOME%\include +set PYTHON_LIBRARY=%PYTHONHOME%\libs\python%PY_VER_MAJOR_MINOR%.lib +set PYTHON_EXECUTABLE=%PYTHONHOME%\python.exe set SWIG_DIR=%INSTALL_DIR%\swigwin -set PATH=%PATH%;%SWIG_DIR%;%PYTHONPATH% +set PATH=%PATH%;%SWIG_DIR%;%PYTHONHOME% :: TODO 3ds Max SDK? echo. @@ -75,7 +75,7 @@ echo OCC_INCLUDE_DIR = %OCC_INCLUDE_DIR% echo OCC_LIBRARY_DIR = %OCC_LIBRARY_DIR% echo OPENCOLLADA_INCLUDE_DIR = %OPENCOLLADA_INCLUDE_DIR% echo OPENCOLLADA_LIBRARY_DIR = %OPENCOLLADA_LIBRARY_DIR% -echo PYTHONPATH = %PYTHONPATH% +echo PYTHONHOME = %PYTHONHOME% echo PYTHON_INCLUDE_DIR = %PYTHON_INCLUDE_DIR% echo PYTHON_LIBRARY = %PYTHON_LIBRARY% echo PYTHON_EXECUTABLE = %PYTHON_EXECUTABLE% diff --git a/win/set-python-to-path.bat b/win/set-python-to-path.bat index 613a69c149..b9f225be7a 100644 --- a/win/set-python-to-path.bat +++ b/win/set-python-to-path.bat @@ -27,10 +27,10 @@ if not exist BuildDepsCache-%TARGET_ARCH%.txt. ( goto :EOF ) for /f "delims== tokens=1,2" %%G in (BuildDepsCache-%TARGET_ARCH%.txt) do set %%G=%%H -if not defined PYTHONPATH ( - echo PYTHONPATH PYTHONPATH not defined +if not defined PYTHONHOME ( + echo PYTHONHOME PYTHONHOME not defined goto :EOF ) -echo %PYTHONPATH% set to PATH -set PATH=%PYTHONPATH%;%PATH% +echo %PYTHONHOME% set to PATH +set PATH=%PYTHONHOME%;%PATH%