diff --git a/CMake/CMakeLists_executable.txt b/CMake/CMakeLists_bin.txt similarity index 96% rename from CMake/CMakeLists_executable.txt rename to CMake/CMakeLists_bin.txt index a20192301a78f7598233639e0ab89363c5c0e304..d67320e18c3cc94d01350cc453b127bd5663679d 100644 --- a/CMake/CMakeLists_executable.txt +++ b/CMake/CMakeLists_bin.txt @@ -3,7 +3,8 @@ project({project_name}) set(PROJECT_NAME {project_name}) set(SOURCE_FILES -{source_files} ) + {source_files} + ) # Add executable target add_executable(${{PROJECT_NAME}} ${{SOURCE_FILES}}) diff --git a/CMake/CMakeLists_library.txt b/CMake/CMakeLists_lib.txt similarity index 96% rename from CMake/CMakeLists_library.txt rename to CMake/CMakeLists_lib.txt index dbb5f946f00d9f1d7211eb56c7615d36e6e129a4..af1942d54368c53f8acb200421138e0639b118ac 100644 --- a/CMake/CMakeLists_library.txt +++ b/CMake/CMakeLists_lib.txt @@ -5,7 +5,8 @@ set(PROJECT_NAME {project_name}) {cmake_options} set(SOURCE_FILES -{source_files} ) + {source_files} + ) # Add library target add_library(${{PROJECT_NAME}} SHARED ${{SOURCE_FILES}}) @@ -43,7 +44,8 @@ set(CMAKE_AUTOUIC OFF) set(PROJECT_NAME_TEST test-{project_name}) set(SOURCE_FILES_TEST -{source_files_test} ) + {source_files_test} + ) add_executable(${{PROJECT_NAME_TEST}} ${{SOURCE_FILES_TEST}}) set_target_properties(${{PROJECT_NAME_TEST}} PROPERTIES diff --git a/CMake/CMakeLists_root.txt b/CMake/CMakeLists_root.txt index 3ea58e86b30cff9e7eda75ad8cdbef3ad83eeab5..660769cdc8cd1ffa74eede9fe42b79f5486f3e42 100644 --- a/CMake/CMakeLists_root.txt +++ b/CMake/CMakeLists_root.txt @@ -109,3 +109,6 @@ endforeach () # - enable enable_testing() # include(CTest) # we do not need full CTest support now + +# register bash tests +# TODO diff --git a/CMake/__init__.py b/CMake/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/CMake/__main__.py b/CMake/__main__.py deleted file mode 100644 index 2141f99ff51f476a383fd5e33a8da9088a6ff149..0000000000000000000000000000000000000000 --- a/CMake/__main__.py +++ /dev/null @@ -1,3 +0,0 @@ -from alib_cmake import main - -main() diff --git a/CMake/alib_cmake.py b/CMake/alib_cmake.py deleted file mode 100755 index f1c039d60329916b643a1382d7d968905f1f2e77..0000000000000000000000000000000000000000 --- a/CMake/alib_cmake.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys - -import click - -alib_path = '..' - -alib_modules_lib = [ - # Libraries - 'alib2algo', - 'alib2algo_experimental', - 'alib2aux', - 'alib2cli', - 'alib2common', - 'alib2data', - 'alib2data_experimental', - 'alib2elgo', - 'alib2measure', - 'alib2raw', - 'alib2raw_cli_integration', - 'alib2std', - 'alib2str', - 'alib2str_cli_integration', - 'alib2xml', - 'alib2abstraction', - 'alib2dummy', - 'alib2graph_data', - 'alib2graph_algo', - 'alib2gui', -] - -alib_modules_exe = [ - # Binaries - 'aaccess2', - 'aarbology2', - 'acast2', - 'acompaction2', - 'acompare2', - 'aconversions2', - 'aconvert2', - 'aderivation2', - 'adeterminize2', - 'aecho2', - 'aepsilon2', - 'agenerate2', - 'aintegral2', - 'aintrospection2', - 'alangop2', - 'aminimize2', - 'anormalize2', - 'aql2', - 'aquery2', - 'arand2', - 'araw2', - 'arename2', - 'areverse2', - 'arun2', - 'astat2', - 'astringology2', - 'atrim2', - 'tniceprint', - 'agui2', -] - -root_template = open(os.path.join(os.path.dirname(__file__), "CMakeLists_root.txt"), 'r').read() -library_template = open(os.path.join(os.path.dirname(__file__), "CMakeLists_library.txt"), 'r').read() -executable_template = open(os.path.join(os.path.dirname(__file__), "CMakeLists_executable.txt"), 'r').read() - -separate_size = 20 - - -# ---------------------------------------------------------------------------------------------------------------------- - -def create_root_cmakelist(debug): - alib_modules_exe_str = '\n '.join(alib_modules_exe) - alib_modules_lib_str = '\n '.join(alib_modules_lib) - - if not debug: - print('CMakeLists.txt') - print('-' * separate_size) - print(root_template.format( - alib_modules_lib=alib_modules_lib_str, - alib_modules_exe=alib_modules_exe_str - )) - print('-' * separate_size) - else: - with open(f'{alib_path}/CMakeLists.txt', 'w') as file: - file.write(root_template.format( - alib_modules_lib=alib_modules_lib_str, - alib_modules_exe=alib_modules_exe_str - )) - - -# ---------------------------------------------------------------------------------------------------------------------- - -def get_source_files(project_name, directory): - # Recursively find all source file(s) and directories - source_files = [] - for dp, dn, fn in os.walk(f'{alib_path}/{project_name}/{directory}'): - for file in fn: - if file.endswith(".cxx") or file.endswith(".hxx") or file.endswith(".txx"): - continue - source_files.append(os.path.join(dp, file)) - - # Create strings from lists for file(s) - source_files_str = "" - for file in source_files: - source_files_str += f' {file[len(alib_path)+1+len(project_name)+1:]}\n' - - return source_files_str - - -# ---------------------------------------------------------------------------------------------------------------------- -def parse_makeconfig(file): - link_libs = [] - link_test_libs = [] - include_libs = [] - include_test_libs = [] - cmake_options = [] - - # Read and parse makefile.conf - with open(file, 'r') as file: - for line in file: - if line.startswith('LINK_LIBRARIES'): - link_libs = line[len('LINK_LIBRARIES='):].split() - elif line.startswith('SYSTEM_LIBRARIES'): - sys_libs = line[len('SYSTEM_LIBRARIES='):].split() - for lib in sys_libs: - if lib == 'xml2': - link_libs.append('${LIBXML2_LIBRARIES}') - include_libs.append('PUBLIC ${LIBXML2_INCLUDE_DIR}') - elif lib == 'threads': - link_libs.append('${CMAKE_THREAD_LIBS_INIT}') - elif lib == 'Qt5Widgets': - link_libs.append('Qt5::Widgets') - include_libs.append('${Qt5Widgets_INCLUDE_DIRS}') - elif lib == 'Qt5Xml': - link_libs.append('Qt5::Xml') - include_libs.append('${Qt5Xml_INCLUDE_DIRS}') - elif lib == 'graphviz': - link_libs.append('${GRAPHVIZ_GVC_LIBRARY}') - link_libs.append('${GRAPHVIZ_CGRAPH_LIBRARY}') - include_libs.append('${GRAPHVIZ_INCLUDE_DIR}') - elif lib == 'json': - link_libs.append('${JSONCPP_LIBRARIES}') - include_libs.append('${jsoncpp_INCLUDE_DIRS}') - else: - link_libs.append(lib) - elif line.startswith('TEST_LINK_LIBRARIES'): - link_test_libs = line[len('TEST_LINK_LIBRARIES='):].split() - elif line.startswith('TEST_SYSTEM_LIBRARIES'): - sys_libs = line[len('TEST_SYSTEM_LIBRARIES='):].split() - for lib in sys_libs: - link_test_libs.append() - elif line.startswith('AUTOMOC=ON'): - cmake_options.append('set(CMAKE_AUTOMOC ON)') - elif line.startswith('AUTOUIC=ON'): - cmake_options.append('set(CMAKE_AUTOUIC ON)') - - return ' '.join(link_libs), ' '.join(link_test_libs), ' '.join(include_libs), ' '.join(include_test_libs), '\n'.join(cmake_options) - - -# ---------------------------------------------------------------------------------------------------------------------- - -def create_library_package(project_name, write): - # Parse config file - link_libs, link_test_libs, include_libs, include_test_libs, cmake_options = parse_makeconfig(f'{alib_path}/{project_name}/makefile.conf') - - # Get source files - source_files = get_source_files(project_name, 'src') - - # Get source files test - source_files_test = get_source_files(project_name, 'test-src') - - if not write: - print(f'{project_name}/CMakeLists.txt') - print('-' * separate_size) - print(library_template.format( - project_name=project_name, - target_libs=link_libs, - target_test_libs=link_test_libs, - include_paths=include_libs, - include_test_paths=include_test_libs, - cmake_options=cmake_options, - source_files=source_files, - source_files_test=source_files_test, - )) - print('-' * separate_size) - else: - with open(f'{alib_path}/{project_name}/CMakeLists.txt', 'w') as file: - file.write(library_template.format( - project_name=project_name, - target_libs=link_libs, - target_test_libs=link_test_libs, - include_paths=include_libs, - include_test_paths=include_test_libs, - cmake_options=cmake_options, - source_files=source_files, - source_files_test=source_files_test, - )) - - -# ---------------------------------------------------------------------------------------------------------------------- - -def create_executable_package(project_name, write): - # Parse config file - link_libs, link_test_libs, include_libs, include_test_libs, cmake_options = parse_makeconfig(f'{alib_path}/{project_name}/makefile.conf') - - # Get source files - source_files = get_source_files(project_name, 'src') - - if not write: - print(f'{project_name}/CMakeLists.txt') - print('-' * separate_size) - print(executable_template.format( - project_name=project_name, - target_libs=link_libs, - target_test_libs=link_test_libs, - include_paths=include_libs, - include_test_paths=include_test_libs, - cmake_options=cmake_options, - source_files=source_files, - )) - print('-' * separate_size) - else: - with open(f'{alib_path}/{project_name}/CMakeLists.txt', 'w') as file: - file.write(executable_template.format( - project_name=project_name, - target_libs=link_libs, - target_test_libs=link_test_libs, - include_paths=include_libs, - include_test_paths=include_test_libs, - cmake_options=cmake_options, - source_files=source_files, - )) - - -# ---------------------------------------------------------------------------------------------------------------------- - -@click.command() -@click.option('--packages', '-p', help='Specify packages', default=alib_modules_lib + alib_modules_exe, multiple=True) -@click.option('--write', '-w', help='Write output to file(s).', is_flag=True, default=False) -@click.option('--main_file', '-m', help='Generate also main CMakeLists.txt', is_flag=True, default=False) -def main(write, main_file, packages): - packages_cnt = len(packages) - libs_cnt = len(list(set(packages) & set(alib_modules_lib))) - exes_cnt = len(list(set(packages) & set(alib_modules_exe))) - - # Increment counter - if main_file: - packages_cnt += 1 - - # Generate for library package - for i, package in enumerate(list(set(packages) & set(alib_modules_lib)), 1): - try: - create_library_package(package, write) - print(f'[{i}/{packages_cnt}] Generated library package {package}', file=sys.stderr) - except FileNotFoundError as e: - print(f'[{i}/{packages_cnt}] Skipping library package {package}: {e}', file=sys.stderr) - - # Generate for executable package - for i, package in enumerate(list(set(packages) & set(alib_modules_exe)), libs_cnt + 1): - try: - create_executable_package(package, write) - print(f'[{i}/{packages_cnt}] Generated executable package {package}', file=sys.stderr) - except FileNotFoundError as e: - print(f'[{i}/{packages_cnt}] Skipping executable package {package}: {e}', file=sys.stderr) - - # Generate root file - if main_file: - create_root_cmakelist(write) - print(f'[{packages_cnt}/{packages_cnt}] Generated main CMakeLists.txt', file=sys.stderr) - - -# ---------------------------------------------------------------------------------------------------------------------- - -if __name__ == '__main__': - main() diff --git a/CMake/config.ini b/CMake/config.ini new file mode 100644 index 0000000000000000000000000000000000000000..4d15d9b95d0b925d112ece08e3f71bbe087d2dd5 --- /dev/null +++ b/CMake/config.ini @@ -0,0 +1,57 @@ +[Templates] +root = CMakeLists_root.txt +lib = CMakeLists_lib.txt +bin = CMakeLists_bin.txt + +[ModulesLib] +alib2algo +alib2algo_experimental +alib2aux +alib2cli +alib2common +alib2data +alib2data_experimental +alib2elgo +alib2measure +alib2raw +alib2raw_cli_integration +alib2std +alib2str +alib2str_cli_integration +alib2xml +alib2abstraction +alib2dummy +alib2graph_data +alib2graph_algo +alib2gui + +[ModulesBin] +aaccess2 +aarbology2 +acast2 +acompaction2 +acompare2 +aconversions2 +aconvert2 +aderivation2 +adeterminize2 +aecho2 +aepsilon2 +agenerate2 +aintegral2 +aintrospection2 +alangop2 +aminimize2 +anormalize2 +aql2 +aquery2 +arand2 +araw2 +arename2 +areverse2 +arun2 +astat2 +astringology2 +atrim2 +tniceprint +agui2 diff --git a/CMake/generate.py b/CMake/generate.py new file mode 100755 index 0000000000000000000000000000000000000000..6ec1dd79332cf6c825d6b02efea5fa73839c2662 --- /dev/null +++ b/CMake/generate.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 + +import os +import sys +import configparser +import argparse + +# ---------------------------------------------------------------------------------------------------------------------- + + +class SmartOpen: + def __init__(self, filename, mode='r', *, directory='.', encoding=None, dry_run=False): + self._dry_run = dry_run + self._filename = filename + self._mode = mode + + if self._dry_run: + self._fd = sys.stdout + else: + self._fd = open(os.path.join(directory, filename), mode=mode, encoding=encoding) + + def read(self): + return self._fd.read() + + def __enter__(self): + if self._dry_run and 'w' in self._mode: + self._fd.write(f'{self._filename}\n' + '-' * SEPARATOR_SIZE + '\n') + + return self._fd + + def __exit__(self, d_type, value, traceback): + if self._dry_run and 'w' in self._mode: + self._fd.write('-' * SEPARATOR_SIZE + '\n') + + if self._fd != sys.stdout: + self._fd.close() + +# ---------------------------------------------------------------------------------------------------------------------- + + +SCRIPT_DIRECTORY = os.path.join(os.path.dirname(__file__)) +ALIB_DIRECTORY = os.path.join(SCRIPT_DIRECTORY, "..") +SEPARATOR_SIZE = 20 + +SOURCES_EXCLUDE = ('.cxx', '.hxx', '.txx') + +config = configparser.ConfigParser(allow_no_value=True) +config.read(os.path.join(SCRIPT_DIRECTORY, 'config.ini')) + +# ---------------------------------------------------------------------------------------------------------------------- + + +PACKAGES = { + 'lib': {key for key in config['ModulesLib']}, + 'bin': {key for key in config['ModulesBin']}, +} + +TEMPLATES = { + tpl: SmartOpen(config['Templates'][tpl], directory=SCRIPT_DIRECTORY, mode='r').read() for tpl in ['root', 'lib', 'bin'] +} + + +# ---------------------------------------------------------------------------------------------------------------------- + + +def to_rows(lst, sep='\n '): + return sep.join(lst) + +# ---------------------------------------------------------------------------------------------------------------------- + + +def get_source_files(project_name, directory): + # Recursively find all source file(s) and directories + source_files = [] + relpath_ref = os.path.join(ALIB_DIRECTORY, project_name) + + for dp, dn, fn in os.walk(os.path.join(relpath_ref, directory)): + source_files = source_files + [os.path.relpath(os.path.join(dp, file), relpath_ref) + for file in fn if not file.endswith(SOURCES_EXCLUDE)] + + return source_files + +# ---------------------------------------------------------------------------------------------------------------------- + + +def parse_makeconfig(file): + link_libs = [] + link_test_libs = [] + include_libs = [] + include_test_libs = [] + cmake_options = [] + + # Read and parse makefile.conf + with open(file, 'r') as file: + for line in file: + if line.startswith('LINK_LIBRARIES'): + link_libs = line[len('LINK_LIBRARIES='):].split() + elif line.startswith('SYSTEM_LIBRARIES'): + sys_libs = line[len('SYSTEM_LIBRARIES='):].split() + for lib in sys_libs: + if lib == 'xml2': + link_libs.append('${LIBXML2_LIBRARIES}') + include_libs.append('PUBLIC ${LIBXML2_INCLUDE_DIR}') + elif lib == 'threads': + link_libs.append('${CMAKE_THREAD_LIBS_INIT}') + elif lib == 'Qt5Widgets': + link_libs.append('Qt5::Widgets') + include_libs.append('${Qt5Widgets_INCLUDE_DIRS}') + elif lib == 'Qt5Xml': + link_libs.append('Qt5::Xml') + include_libs.append('${Qt5Xml_INCLUDE_DIRS}') + elif lib == 'graphviz': + link_libs.append('${GRAPHVIZ_GVC_LIBRARY}') + link_libs.append('${GRAPHVIZ_CGRAPH_LIBRARY}') + include_libs.append('${GRAPHVIZ_INCLUDE_DIR}') + elif lib == 'json': + link_libs.append('${JSONCPP_LIBRARIES}') + include_libs.append('${jsoncpp_INCLUDE_DIRS}') + else: + link_libs.append(lib) + elif line.startswith('TEST_LINK_LIBRARIES'): + link_test_libs = line[len('TEST_LINK_LIBRARIES='):].split() + elif line.startswith('TEST_SYSTEM_LIBRARIES'): + sys_libs = line[len('TEST_SYSTEM_LIBRARIES='):].split() + for lib in sys_libs: + link_test_libs.append() + elif line.startswith('AUTOMOC=ON'): + cmake_options.append('set(CMAKE_AUTOMOC ON)') + elif line.startswith('AUTOUIC=ON'): + cmake_options.append('set(CMAKE_AUTOUIC ON)') + + return ' '.join(link_libs), ' '.join(link_test_libs), ' '.join(include_libs), ' '.join( + include_test_libs), '\n'.join(cmake_options) + +# ---------------------------------------------------------------------------------------------------------------------- + + +def create_root_cmakelist(dry_run, packages): + with SmartOpen("CMakeLists.txt", 'w', directory=ALIB_DIRECTORY, dry_run=dry_run) as f: + f.write(TEMPLATES['root'].format( + alib_modules_lib=to_rows(packages['library']), + alib_modules_exe=to_rows(packages['executable']), + )) + + if dry_run: + f.write('-' * SEPARATOR_SIZE + '\n') + + +def create_library_package(project_name, dry_run): + link_libs, link_test_libs, include_libs, include_test_libs, cmake_options = parse_makeconfig( + os.path.join(ALIB_DIRECTORY, project_name, 'makefile.conf')) + + with SmartOpen("CMakeLists.txt", 'w', directory=os.path.join(ALIB_DIRECTORY, project_name), dry_run=dry_run) as f: + f.write(TEMPLATES['lib'].format( + project_name=project_name, + target_libs=link_libs, + target_test_libs=link_test_libs, + include_paths=include_libs, + include_test_paths=include_test_libs, + cmake_options=cmake_options, + source_files=to_rows(get_source_files(project_name, 'src')), + source_files_test=to_rows(get_source_files(project_name, 'test-src')), + )) + + +def create_executable_package(project_name, dry_run): + link_libs, link_test_libs, include_libs, include_test_libs, cmake_options = parse_makeconfig( + os.path.join(ALIB_DIRECTORY, project_name, 'makefile.conf')) + + with SmartOpen("CMakeLists.txt", 'w', directory=os.path.join(ALIB_DIRECTORY, project_name), dry_run=dry_run) as f: + f.write(TEMPLATES['bin'].format( + project_name=project_name, + target_libs=link_libs, + target_test_libs=link_test_libs, + include_paths=include_libs, + include_test_paths=include_test_libs, + cmake_options=cmake_options, + source_files=to_rows(get_source_files(project_name, 'src')), + )) + +# ---------------------------------------------------------------------------------------------------------------------- + + +def main(dry_run, main_file, packages): + packages = { + 'library': set(packages) & PACKAGES['lib'], + 'executable': set(packages) & PACKAGES['bin'], + } + + packages_functions = { + 'library': create_library_package, + 'executable': create_executable_package, + } + + packages_cnt = sum([len(v) for k, v in packages.items()]) + (main_file is True) + + i = 1 + for type, packages_set in packages.items(): + for package in packages_set: + try: + packages_functions[type](package, dry_run) + print(f'[{i}/{packages_cnt}] Generated {type} package {package}', file=sys.stderr) + except FileNotFoundError as e: + print(f'[{i}/{packages_cnt}] Skipping library package {package}: {e}', file=sys.stderr) + + i += 1 + + # Generate root file + if main_file: + create_root_cmakelist(dry_run, packages) + print(f'[{i}/{packages_cnt}] Generated main CMakeLists.txt', file=sys.stderr) + +# ---------------------------------------------------------------------------------------------------------------------- + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='CMakeLists generator for Algorithms Library Toolkit') + parser.add_argument('-w', '--write', action='store_true', default=False, help="Write files") + parser.add_argument('-m', '--main', action='store_true', default=False, help="Generate main CMakeLists.txt") + parser.add_argument('-p', '--packages', action='append', help='Specify packages to build. For multiple packages, use -p multiple times') + + args = parser.parse_args() + + if args.packages is None: + args.packages = list(PACKAGES['lib'] | PACKAGES['bin']) + + main(not args.write, args.main, args.packages) diff --git a/CMake/requirements.txt b/CMake/requirements.txt deleted file mode 100644 index 3af12f5c89c416fd8c1820c52d7f870c42414e50..0000000000000000000000000000000000000000 --- a/CMake/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -click==6.7