Rewritten CMake installation directives, added setup.py for libuavcan_dsdl_compiler. uavcan_dsdlc should be lifted from libuavcan to a separate subproject in order to add support for other programming languages

This commit is contained in:
Pavel Kirienko
2014-03-29 14:31:27 +04:00
parent 77d46cb91f
commit e212c6a9d5
6 changed files with 108 additions and 58 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
lib*.so
lib*.so.*
*.a
*/build
build
.dep
__pycache__
+13 -8
View File
@@ -2,7 +2,7 @@
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION 2.8)
if(DEFINED CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Debug Release RelWithDebInfo MinSizeRel")
@@ -31,9 +31,10 @@ endif ()
# DSDL compiler invocation
# Probably output files should be saved into CMake output dir?
#
execute_process(COMMAND ./setup.py build WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/dsdl_compiler)
set(DSDLC_INPUTS "test/dsdl_test/root_ns_a" "test/dsdl_test/root_ns_b" "${CMAKE_SOURCE_DIR}/../dsdl/uavcan")
set(DSDLC_OUTPUT "include/dsdlc_generated")
add_custom_target(dsdlc dsdl_compiler/dsdlc.py ${DSDLC_INPUTS} -O${DSDLC_OUTPUT}
add_custom_target(dsdlc dsdl_compiler/uavcan_dsdlc ${DSDLC_INPUTS} -O${DSDLC_OUTPUT}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
include_directories(${DSDLC_OUTPUT})
@@ -64,10 +65,12 @@ file(GLOB_RECURSE LIBUAVCAN_CXX_FILES RELATIVE ${CMAKE_SOURCE_DIR} "src/*.cpp")
add_library(uavcan SHARED ${LIBUAVCAN_CXX_FILES})
add_dependencies(uavcan dsdlc)
install(TARGETS uavcan DESTINATION lib)
install(DIRECTORY include/uavcan DESTINATION include)
install(DIRECTORY include/dsdlc_generated/uavcan DESTINATION include) # Merging generated .hpp with lib's .hpp
install(DIRECTORY src/ DESTINATION src/uavcan)
install(TARGETS uavcan DESTINATION lib)
install(DIRECTORY include/uavcan DESTINATION include)
install(DIRECTORY include/dsdlc_generated/uavcan DESTINATION include) # Generated and lib's .hpp
install(DIRECTORY src DESTINATION src/uavcan)
install(DIRECTORY ../dsdl DESTINATION share/uavcan) # TODO: move to top-level CMake script
install(CODE "execute_process(COMMAND ./setup.py install WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/dsdl_compiler)")
#
# Tests and static analysis - only for debug builds
@@ -91,8 +94,8 @@ function(add_libuavcan_test name library flags) # Adds GTest executable and crea
# Tests run automatically upon successful build
# If failing tests need to be investigated with debugger, use 'make --ignore-errors'
add_custom_command(TARGET ${name} POST_BUILD
COMMAND ./${name} > "${name}.log"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
COMMAND ./${name} > "${name}.log"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endfunction()
if (DEBUG_BUILD)
@@ -109,9 +112,11 @@ if (DEBUG_BUILD)
# Additional flavours of the library
add_library(uavcan_cpp03 SHARED ${LIBUAVCAN_CXX_FILES})
set_target_properties(uavcan_cpp03 PROPERTIES COMPILE_FLAGS ${cpp03_flags})
add_dependencies(uavcan_cpp03 dsdlc)
add_library(uavcan_optim SHARED ${LIBUAVCAN_CXX_FILES})
set_target_properties(uavcan_optim PROPERTIES COMPILE_FLAGS ${optim_flags})
add_dependencies(uavcan_optim dsdlc)
# GTest executables
find_package(GTest REQUIRED)
@@ -1,19 +1,11 @@
#!/usr/bin/env python3
#
# UAVCAN DSDL compiler for libuavcan
#
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
import sys, os, argparse, logging, errno
import sys, os, logging, errno
from mako.template import Template
RUNNING_FROM_SRC_DIR = os.path.abspath(__file__).endswith(os.path.join('libuavcan', 'dsdl_compiler', 'dsdlc.py'))
if RUNNING_FROM_SRC_DIR:
print('Running from the source directory')
scriptdir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(scriptdir, '..', '..', 'pyuavcan'))
from pyuavcan import dsdl
MAX_BITLEN_FOR_ENUM = 31
@@ -21,11 +13,27 @@ OUTPUT_FILE_EXTENSION = 'hpp'
OUTPUT_FILE_PERMISSIONS = 0o444 # Read only for all
TEMPLATE_FILENAME = os.path.join(os.path.dirname(__file__), 'data_type_template.tmpl')
# -----------------
__all__ = ['run', 'logger', 'DsdlCompilerException']
class DsdlCompilerException(Exception):
pass
logger = logging.getLogger(__name__)
def run(source_dirs, include_dirs, output_dir):
assert isinstance(source_dirs, list)
assert isinstance(include_dirs, list)
assert isinstance(output_dir, str)
types = run_parser(source_dirs, include_dirs + source_dirs)
if not types:
die('No type definitions were found')
logger.info('%d types total', len(types))
run_generator(types, output_dir)
# -----------------
def pretty_filename(filename):
a = os.path.abspath(filename)
r = os.path.relpath(filename)
@@ -43,20 +51,14 @@ def makedirs(path):
raise
def die(text):
print(text, file=sys.stderr)
exit(1)
def configure_logging(verbosity):
fmt = '%(message)s'
level = { 0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG }.get(verbosity or 0, logging.DEBUG)
logging.basicConfig(stream=sys.stderr, level=level, format=fmt)
raise DsdlCompilerException(str(text))
def run_parser(source_dirs, search_dirs):
try:
types = dsdl.parse_namespaces(source_dirs, search_dirs)
except dsdl.DsdlException as ex:
logging.info('Parser failure', exc_info=True)
die(str(ex))
logger.info('Parser failure', exc_info=True)
die(ex)
return types
def run_generator(types, dest_dir):
@@ -64,13 +66,13 @@ def run_generator(types, dest_dir):
dest_dir = os.path.abspath(dest_dir) # Removing '..'
makedirs(dest_dir)
for t in types:
logging.info('Generating type %s', t.full_name)
logger.info('Generating type %s', t.full_name)
filename = os.path.join(dest_dir, type_output_filename(t))
text = generate_one_type(t)
write_generated_data(filename, text)
except Exception as ex:
logging.info('Generator failure', exc_info=True)
die(str(ex))
logger.info('Generator failure', exc_info=True)
die(ex)
def write_generated_data(filename, data):
dirname = os.path.dirname(filename)
@@ -81,12 +83,12 @@ def write_generated_data(filename, data):
with open(filename) as f:
existing_data = f.read()
if data == existing_data:
logging.info('Up to date [%s]', pretty_filename(filename))
logger.info('Up to date [%s]', pretty_filename(filename))
return
logging.info('Rewriting [%s]', pretty_filename(filename))
logger.info('Rewriting [%s]', pretty_filename(filename))
os.remove(filename)
else:
logging.info('Creating [%s]', pretty_filename(filename))
logger.info('Creating [%s]', pretty_filename(filename))
# Full rewrite
with open(filename, 'w') as f:
@@ -94,7 +96,7 @@ def write_generated_data(filename, data):
try:
os.chmod(filename, OUTPUT_FILE_PERMISSIONS)
except (OSError, IOError) as ex:
logging.warning('Failed to set permissions for %s: %s', pretty_filename(filename), ex)
logger.warning('Failed to set permissions for %s: %s', pretty_filename(filename), ex)
def type_to_cpp_type(t):
if t.category == t.CATEGORY_PRIMITIVE:
@@ -192,26 +194,3 @@ def generate_one_type(t):
text = text.replace('\n\n\n\n', '\n\n').replace('\n\n\n', '\n\n')
text = text.replace('{\n\n ', '{\n ')
return text
# -----------------
DESCRIPTION = '''UAVCAN DSDL compiler. Takes an input directory that contains an hierarchy of DSDL
definitions and converts it into compatible hierarchy of C++ types for libuavcan.'''
DEFAULT_OUTDIR = './dsdlc_generated'
argparser = argparse.ArgumentParser(description=DESCRIPTION)
argparser.add_argument('source_dir', nargs='+', help='source directory with DSDL definitions')
argparser.add_argument('--verbose', '-v', action='count', help='verbosity level (-v, -vv)')
argparser.add_argument('--outdir', '-O', default=DEFAULT_OUTDIR, help='output directory, default %s' % DEFAULT_OUTDIR)
argparser.add_argument('--incdir', '-I', default=[], action='append', help='nested type namespaces')
args = argparser.parse_args()
configure_logging(args.verbose)
types = run_parser(args.source_dir, args.incdir + args.source_dir)
if not types:
die('No type definitions were found')
logging.info('%d types total', len(types))
run_generator(types, args.outdir)
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env python3
from distutils.core import setup
args = dict(
name='uavcan_dsdlc',
version='0.1',
description='UAVCAN DSDL compiler for libuavcan',
packages=['libuavcan_dsdl_compiler'],
package_data={'libuavcan_dsdl_compiler': ['data_type_template.tmpl']},
scripts=['uavcan_dsdlc'],
requires=['mako', 'pyuavcan'],
author='Pavel Kirienko',
author_email='pavel.kirienko@gmail.com',
url='http://uavcan.org',
license='MIT'
)
setup(**args)
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python3
#
# UAVCAN DSDL compiler
# Probably it will be extended in future to add support for different programming languages.
#
# Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
#
import os, sys, logging, argparse
def configure_logging(verbosity):
fmt = '%(message)s'
level = { 0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG }.get(verbosity or 0, logging.DEBUG)
logging.basicConfig(stream=sys.stderr, level=level, format=fmt)
def die(text):
print(text, file=sys.stderr)
exit(1)
RUNNING_FROM_SRC_DIR = os.path.abspath(__file__).endswith(os.path.join('libuavcan', 'dsdl_compiler', 'uavcan_dsdlc'))
if RUNNING_FROM_SRC_DIR:
print('Running from the source directory')
scriptdir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(scriptdir, '..', '..', 'pyuavcan'))
sys.path.append(os.path.join(scriptdir))
DEFAULT_OUTDIR = './dsdlc_generated'
DESCRIPTION = '''UAVCAN DSDL compiler. Takes an input directory that contains an hierarchy of DSDL
definitions and converts it into compatible hierarchy of C++ types for libuavcan.'''
argparser = argparse.ArgumentParser(description=DESCRIPTION)
argparser.add_argument('source_dir', nargs='+', help='source directory with DSDL definitions')
argparser.add_argument('--verbose', '-v', action='count', help='verbosity level (-v, -vv)')
argparser.add_argument('--outdir', '-O', default=DEFAULT_OUTDIR, help='output directory, default %s' % DEFAULT_OUTDIR)
argparser.add_argument('--incdir', '-I', default=[], action='append', help='nested type namespaces')
args = argparser.parse_args()
configure_logging(args.verbose)
from libuavcan_dsdl_compiler import run as dsdlc_run
try:
# TODO: collect include dirs from environment variable UAVCAN_DSDL_INCLUDE
dsdlc_run(args.source_dir, args.incdir, args.outdir)
except Exception as ex:
logging.error('Compiler failure', exc_info=True)
die(str(ex))