diff options
author | arcadia-devtools <arcadia-devtools@yandex-team.ru> | 2022-03-29 15:08:25 +0300 |
---|---|---|
committer | arcadia-devtools <arcadia-devtools@yandex-team.ru> | 2022-03-29 15:08:25 +0300 |
commit | 6eea9d2f39fb9f4d899efd685c872e4b8ede680f (patch) | |
tree | fede9620276c8eafb0c51ff2ddd8e914be89f247 | |
parent | 5f65d38427c0df2cc82db30c0363c6aa5d4d856e (diff) | |
download | ydb-6eea9d2f39fb9f4d899efd685c872e4b8ede680f.tar.gz |
intermediate changes
ref:b63d6b71507593ba174dde46e5c3aee4e9ccd498
-rw-r--r-- | build/scripts/export_script_gen.py | 123 | ||||
-rw-r--r-- | cmake/yandex_common.cmake | 41 |
2 files changed, 164 insertions, 0 deletions
diff --git a/build/scripts/export_script_gen.py b/build/scripts/export_script_gen.py new file mode 100644 index 0000000000..269af2e3ca --- /dev/null +++ b/build/scripts/export_script_gen.py @@ -0,0 +1,123 @@ +import argparse +import collections +import sys + + +def parse_export_file(src): + for line in src: + line = line.strip() + + if line and '#' not in line: + words = line.split() + if len(words) == 2 and words[0] == 'linux_version': + yield {'linux_version': words[1]} + elif len(words) == 2: + yield {'lang': words[0], 'sym': words[1]} + elif len(words) == 1: + yield {'lang': 'C', 'sym': words[0]} + else: + raise Exception('unsupported exports line: "{}"'.format(line)) + + +def to_c(sym): + symbols = collections.deque(sym.split('::')) + c_prefixes = [ # demangle prefixes for c++ symbols + '_ZN', # namespace + '_ZTIN', # typeinfo for + '_ZTSN', # typeinfo name for + '_ZTTN', # VTT for + '_ZTVN', # vtable for + '_ZNK', # const methods + ] + c_sym = '' + while symbols: + s = symbols.popleft() + if s == '*': + c_sym += '*' + break + if '*' in s and len(s) > 1: + raise Exception('Unsupported format, cannot guess length of symbol: ' + s) + c_sym += str(len(s)) + s + if symbols: + raise Exception('Unsupported format: ' + sym) + if c_sym[-1] != '*': + c_sym += 'E*' + return ['{prefix}{sym}'.format(prefix=prefix, sym=c_sym) for prefix in c_prefixes] + + +def to_gnu(src, dest): + d = collections.defaultdict(list) + version = None + for item in parse_export_file(src): + if item.get('linux_version'): + if not version: + version = item.get('linux_version') + else: + raise Exception('More than one linux_version defined') + elif item['lang'] == 'C++': + d['C'].extend(to_c(item['sym'])) + else: + d[item['lang']].append(item['sym']) + + if version: + dest.write('{} {{\nglobal:\n'.format(version)) + else: + dest.write('{\nglobal:\n') + + for k, v in d.items(): + dest.write(' extern "' + k + '" {\n') + + for x in v: + dest.write(' ' + x + ';\n') + + dest.write(' };\n') + + dest.write('local: *;\n};\n') + + +def to_msvc(src, dest): + dest.write('EXPORTS\n') + for item in parse_export_file(src): + if item.get('linux_version'): + continue + if item.get('lang') == 'C': + dest.write(' {}\n'.format(item.get('sym'))) + + +def to_darwin(src, dest): + for item in parse_export_file(src): + if item.get('linux_version'): + continue + + if item['lang'] == 'C': + dest.write('-Wl,-exported_symbol,_' + item['sym']) + elif item['lang'] == 'C++': + for sym in to_c(item['sym']): + dest.write('-Wl,-exported_symbol,_' + sym) + else: + raise Exception('unsupported lang: ' + item['lang']) + + +def main(): + parser = argparse.ArgumentParser(description='Convert self-invented platform independent export file format to the format required by specific linker') + parser.add_argument('src', type=argparse.FileType('r', encoding='UTF-8'), help='platform independent export file path') + parser.add_argument('dest', type=argparse.FileType('w', encoding='UTF-8'), help='destination export file for required linker') + parser.add_argument('--format', help='destination file type format: gnu, msvc or darwin') + + args = parser.parse_args() + if args.format == 'gnu': + to_gnu(args.src, args.dest) + elif args.format == 'msvc': + to_msvc(args.src, args.dest) + elif args.format == 'darwin': + to_darwin(args.src, args.dest) + else: + print('Unknown destination file format: {}'.format(args.format), file=sys.stderr) + sys.exit(1) + + args.src.close() + args.dest.close() + + +if __name__ == '__main__': + main() diff --git a/cmake/yandex_common.cmake b/cmake/yandex_common.cmake index 4efaad97b4..0701afbda6 100644 --- a/cmake/yandex_common.cmake +++ b/cmake/yandex_common.cmake @@ -1,6 +1,7 @@ # Set of common macros find_package(Python2 REQUIRED) +find_package(Python3 REQUIRED) function(target_ragel_lexers TgtName Key Src) SET(RAGEL_BIN ${CMAKE_BINARY_DIR}/bin/ragel) @@ -122,3 +123,43 @@ function(resources Tgt Output) DEPENDS ${RESOURCE_ARGS_INPUTS} ) endfunction() + +function(use_export_script Target ExportFile) + get_filename_component(OutName ${ExportFile} NAME) + set(OutPath ${CMAKE_CURRENT_BINARY_DIR}/gen_${OutName}) + + if (MSVC) + target_link_flags(${Target} PRIVATE /DEF:${OutPath}) + set(EXPORT_SCRIPT_FLAVOR msvc) + elseif(APPLE) + execute_process( + COMMAND Python3_EXECUTABLE ${CMAKE_SOURCE_DIR}/build/scripts/export_script_gen.py ${ExportFile} --format darwin + RESULT_VARIABLE _SCRIPT_RES + OUTPUT_VARIABLE _SCRIPT_FLAGS + ERROR_VARIABLE _SCRIPT_STDERR + ) + if (NOT ${_SCRIPT_RES} EQUAL 0) + message(FATAL_ERROR "Failed to parse export symbols from ${ExportFile}:\n${_SCRIPT_STDERR}") + return() + endif() + target_link_flags(${Target} PRIVATE ${_SCRIPT_FLAGS}) + return() + else() + set(EXPORT_SCRIPT_FLAVOR gnu) + target_link_flags(${Target} PRIVATE -Wl,--gc-sections -rdynamic -Wl,--version-script=${OutPath}) + endif() + + add_custom_command( + OUTPUT ${OutPath} + COMMAND + Python3::Interpreter ${CMAKE_SOURCE_DIR}/build/scripts/export_script_gen.py ${ExportFile} ${OutPath} --format ${EXPORT_SCRIPT_FLAVOR} + DEPENDS ${ExportFile} ${CMAKE_SOURCE_DIR}/build/scripts/export_script_gen.py + ) + target_sources(${Target} PRIVATE ${OutPath}) + set_property(SOURCE ${OutPath} PROPERTY + HEADER_FILE_ONLY On + ) + set_property(TARGET ${Target} APPEND PROPERTY + LINK_DEPENDS ${OutPath} + ) +endfunction() |