Skip to content

Commit

Permalink
Make IO handlers arguments to PODIO_GENERATE_DATAMODEL
Browse files Browse the repository at this point in the history
Making the generator accept (and require) these as command line
arguments allows for a bit more flexibility in defining I/O backends.
For backwards compatibility the additional argument to
PODIO_GENERATE_DATAMODEL is currently made optional and defaults to only
the ROOT backend.
  • Loading branch information
tmadlener committed Sep 17, 2020
1 parent 6900355 commit 36cbd12
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,14 @@ find_package(ROOT REQUIRED COMPONENTS RIO Tree)
if(ROOT_VERSION VERSION_LESS 6.14)
set_property(TARGET ROOT::Core APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${ROOT_INCLUDE_DIRS}")
endif()
list(APPEND PODIO_IO_HANDLERS ROOT)

#--- optionally build with SIO -------------------------------------------------
if(ENABLE_SIO)
find_package( SIO REQUIRED)
if (SIO_FOUND)
MESSAGE( STATUS "Found SIO library - will build SIO I/O support" )
list(APPEND PODIO_IO_HANDLERS SIO)
endif()
endif()

Expand Down
14 changes: 11 additions & 3 deletions cmake/podioMacros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ endfunction()
#---------------------------------------------------------------------------------------------------
#---PODIO_GENERATE_DATAMODEL( datamodel YAML_FILE RETURN_HEADERS RETURN_SOURCES
# OUTPUT_FOLDER output_directory
# IO_BACKEND_HANDLERS io_handlers
# )
#
# Arguments:
Expand All @@ -111,20 +112,27 @@ endfunction()
# Parameters:
# OUTPUT_FOLDER OPTIONAL: The folder in which the output files should be placed
# Default is ${CMAKE_CURRENT_SOURCE_DIR}
# IO_BACKEND_HANDLERS OPTIONAL: The I/O backend handlers that should be generated. The list is
# passed directly to podio_class_generator.py and validated there
# Default is ROOT
# )
#
# Note that the create_${datamodel} target will always be called, but if the YAML_FILE has not changed
# this is essentially a no-op, and should not cause re-compilation.
#---------------------------------------------------------------------------------------------------
function(PODIO_GENERATE_DATAMODEL datamodel YAML_FILE RETURN_HEADERS RETURN_SOURCES)
CMAKE_PARSE_ARGUMENTS(ARG "" "OUTPUT_FOLDER" "" ${ARGN})
CMAKE_PARSE_ARGUMENTS(ARG "" "OUTPUT_FOLDER" "IO_BACKEND_HANDLERS" ${ARGN})
IF(NOT ARG_OUTPUT_FOLDER)
SET(ARG_OUTPUT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
IF(NOT ARG_IO_BACKEND_HANDLERS)
# At least build the ROOT selection.xml by default for now
SET(ARG_IO_BACKEND_HANDLERS "ROOT")
ENDIF()
# we need to boostrap the data model, so this has to be executed in the cmake run
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "Creating \"${datamodel}\" data model"
COMMAND python ${podio_PYTHON_DIR}/podio_class_generator.py ${YAML_FILE} ${ARG_OUTPUT_FOLDER} ${datamodel}
COMMAND python ${podio_PYTHON_DIR}/podio_class_generator.py ${YAML_FILE} ${ARG_OUTPUT_FOLDER} ${datamodel} ${ARG_IO_BACKEND_HANDLERS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

Expand All @@ -138,7 +146,7 @@ function(PODIO_GENERATE_DATAMODEL datamodel YAML_FILE RETURN_HEADERS RETURN_SOUR
COMMENT "Re-Creating \"${datamodel}\" data model"
DEPENDS ${YAML_FILE}
BYPRODUCTS ${sources} ${headers}
COMMAND python ${podio_PYTHON_DIR}/podio_class_generator.py --quiet ${YAML_FILE} ${ARG_OUTPUT_FOLDER} ${datamodel}
COMMAND python ${podio_PYTHON_DIR}/podio_class_generator.py --quiet ${YAML_FILE} ${ARG_OUTPUT_FOLDER} ${datamodel} ${ARG_IO_BACKEND_HANDLERS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

Expand Down
23 changes: 18 additions & 5 deletions python/podio_class_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ def get_clang_format():


class ClassGenerator(object):
def __init__(self, yamlfile, install_dir, package_name, verbose, dryrun):
def __init__(self, yamlfile, install_dir, package_name, io_handlers, verbose, dryrun):
self.install_dir = install_dir
self.package_name = package_name
self.io_handlers = io_handlers
self.verbose = verbose
self.dryrun = dryrun
self.yamlfile = yamlfile
Expand All @@ -85,7 +86,7 @@ def process(self):
for name, datatype in self.reader.datatypes.items():
self._process_datatype(name, datatype)

if 'ROOT' in self.reader.options['IOHandlers']:
if 'ROOT' in self.io_handlers:
self._create_selection_xml()
self.print_report()

Expand Down Expand Up @@ -207,7 +208,7 @@ def _process_datatype(self, name, definition):
self._fill_templates('Obj', datatype)
self._fill_templates('Collection', datatype)

if 'SIO' in self.reader.options["IOHandlers"]:
if 'SIO' in self.io_handlers:
self._fill_templates('SIOBlock', datatype)

def _preprocess_for_obj(self, datatype):
Expand Down Expand Up @@ -400,6 +401,17 @@ def _sort_includes(self, includes):
return package_includes + podio_includes + stl_includes


def verify_io_handlers(handler):
"""Briefly verify that all arguments passed as handlers are indeed valid"""
valid_handlers = (
'ROOT',
'SIO',
)
if handler in valid_handlers:
return handler
raise argparse.ArgumentError('{} is not a valid io handler'.format(handler))


if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Given a description yaml file this script generates '
Expand All @@ -410,7 +422,8 @@ def _sort_includes(self, includes):
'Header files will be put under <targetdir>/<packagename>/*.h. '
'Source files will be put under <targetdir>/src/*.cc')
parser.add_argument('packagename', help='Name of the package.')

parser.add_argument('iohandlers', help='The IO backend specific code that should be generated',
type=verify_io_handlers, nargs='+')
parser.add_argument('-q', '--quiet', dest='verbose', action='store_false', default=True,
help='Don\'t write a report to screen')
parser.add_argument('-d', '--dryrun', action='store_true', default=False,
Expand All @@ -428,7 +441,7 @@ def _sort_includes(self, includes):
if not os.path.exists(directory):
os.makedirs(directory)

gen = ClassGenerator(args.description, args.targetdir, args.packagename,
gen = ClassGenerator(args.description, args.targetdir, args.packagename, args.iohandlers,
verbose=args.verbose, dryrun=args.dryrun)
if args.clangformat:
gen.clang_format = get_clang_format()
Expand Down
2 changes: 0 additions & 2 deletions python/podio_config_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,6 @@ def __init__(self, yamlfile):
"exposePODMembers": True,
# use subfolder when including package header files
"includeSubfolder": False,
# which IOHandlers to generate
"IOHandlers": ['ROOT'],
}
self.warnings = set()

Expand Down
3 changes: 2 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ foreach( _conf ${CMAKE_CONFIGURATION_TYPES} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${_conf} ${CMAKE_CURRENT_BINARY_DIR} )
endforeach()

PODIO_GENERATE_DATAMODEL(datamodel datalayout.yaml headers sources)
PODIO_GENERATE_DATAMODEL(datamodel datalayout.yaml headers sources
IO_BACKEND_HANDLERS ${PODIO_IO_HANDLERS})

if (ENABLE_SIO)
# Filter out the sio block handlers to avoid polluting the TestDataModel lib
Expand Down
1 change: 0 additions & 1 deletion tests/datalayout.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ options :
# should POD members be exposed with getters/setters in classes that have them as members?
exposePODMembers: True
includeSubfolder: True
IOHandlers: ["ROOT"] #,"SIO"]

components :
SimpleStruct:
Expand Down

0 comments on commit 36cbd12

Please sign in to comment.