Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 104 additions & 35 deletions cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# #
################################################################################

cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.5)

project (IfcOpenShell)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -274,34 +275,109 @@ 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)
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")

# 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
if("${COMPILED_SCHEMA_NAME}" STREQUAL "IFC2X3")
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "2x3")
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)
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)
ADD_LIBRARY(IfcParse STATIC ${SOURCE_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 IFCPARSE_CPP_FILES ${SOURCE_FILE})
list(REMOVE_ITEM IFCPARSE_H_FILES ${SOURCE_FILE})
endforeach()
endforeach()

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)

Expand All @@ -312,10 +388,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.
Expand Down Expand Up @@ -343,15 +419,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)
2 changes: 2 additions & 0 deletions src/ifcexpressparser/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,6 @@ def find_keywords(expr, li = None):
implementation.Implementation(mapping).emit()
latebound_header.LateBoundHeader(mapping).emit()
latebound_implementation.LateBoundImplementation(mapping).emit()

sys.stdout.write(schema.name)
"""%('\n'.join(statements)))
34 changes: 34 additions & 0 deletions src/ifcexpressparser/codegen.py
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>. #
# #
###############################################################################

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()
11 changes: 8 additions & 3 deletions src/ifcexpressparser/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,35 @@
# #
###############################################################################

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 = {}
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='"'):
name_to_oid[name] = oid
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]
Expand Down
11 changes: 6 additions & 5 deletions src/ifcexpressparser/enum_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()]))

Expand All @@ -30,9 +31,9 @@ def __init__(self, mapping):
}

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()
12 changes: 6 additions & 6 deletions src/ifcexpressparser/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
# #
###############################################################################

import codegen
import templates
import documentation

class Header:
class Header(codegen.Base):
def __init__(self, mapping):
declarations = []

Expand Down Expand Up @@ -123,10 +124,9 @@ def write_inverse(attr):
}

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()

12 changes: 6 additions & 6 deletions src/ifcexpressparser/implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
# #
###############################################################################

import codegen
import templates

class Implementation:
class Implementation(codegen.Base):
def __init__(self, mapping):
enumeration_functions = []
entity_implementations = []
Expand Down Expand Up @@ -230,10 +231,9 @@ def compose(params):
}

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()

11 changes: 6 additions & 5 deletions src/ifcexpressparser/latebound_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@
# #
###############################################################################

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(),
'schema_name' : mapping.schema.name.capitalize()
}

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()
12 changes: 6 additions & 6 deletions src/ifcexpressparser/latebound_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
# #
###############################################################################

import codegen
import templates

class LateBoundImplementation:
class LateBoundImplementation(codegen.Base):
def __init__(self, mapping):
schema_name = mapping.schema.name.capitalize()

Expand Down Expand Up @@ -110,10 +111,9 @@ def __init__(self, mapping):
}

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()

Loading