From 2831d2f5ecdd0ff616e334aba3f1b8f85fa1e25d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 11 Jun 2024 10:54:05 +0200 Subject: [PATCH] [cmake] fix add_channel_client and add_channel_server only add the channels if they are activated (e.g. both, CHANNEL_ and CHANNEL__CLIENT or CHANNEL__SERVER are defined) --- channels/CMakeLists.txt | 36 ++-- channels/disp/ChannelOptions.cmake | 2 +- channels/rail/ChannelOptions.cmake | 2 +- channels/rdpei/ChannelOptions.cmake | 2 +- channels/rdpgfx/ChannelOptions.cmake | 2 +- checker/abi-suppr.txt | 9 + checker/check-abi | 282 +++++++++++++++++++++++++++ 7 files changed, 315 insertions(+), 20 deletions(-) create mode 100644 checker/abi-suppr.txt create mode 100755 checker/check-abi diff --git a/channels/CMakeLists.txt b/channels/CMakeLists.txt index 4e3fe74e1..f7f2b0c2c 100644 --- a/channels/CMakeLists.txt +++ b/channels/CMakeLists.txt @@ -119,25 +119,29 @@ macro(define_channel_server_subsystem _channel_name _subsystem _type) endmacro(define_channel_server_subsystem) macro(add_channel_client _channel_prefix _channel_name) - add_subdirectory(client) - if(${${_channel_prefix}_CLIENT_STATIC}) - set(CHANNEL_STATIC_CLIENT_MODULES ${CHANNEL_STATIC_CLIENT_MODULES} ${_channel_prefix} PARENT_SCOPE) - set(${_channel_prefix}_CLIENT_NAME ${${_channel_prefix}_CLIENT_NAME} PARENT_SCOPE) - set(${_channel_prefix}_CLIENT_CHANNEL ${${_channel_prefix}_CLIENT_CHANNEL} PARENT_SCOPE) - set(${_channel_prefix}_CLIENT_ENTRY ${${_channel_prefix}_CLIENT_ENTRY} PARENT_SCOPE) - set(CHANNEL_STATIC_CLIENT_ENTRIES ${CHANNEL_STATIC_CLIENT_ENTRIES} ${${_channel_prefix}_CLIENT_ENTRY} PARENT_SCOPE) - endif() + if (${_channel_prefix}_CLIENT) + add_subdirectory(client) + if(${${_channel_prefix}_CLIENT_STATIC}) + set(CHANNEL_STATIC_CLIENT_MODULES ${CHANNEL_STATIC_CLIENT_MODULES} ${_channel_prefix} PARENT_SCOPE) + set(${_channel_prefix}_CLIENT_NAME ${${_channel_prefix}_CLIENT_NAME} PARENT_SCOPE) + set(${_channel_prefix}_CLIENT_CHANNEL ${${_channel_prefix}_CLIENT_CHANNEL} PARENT_SCOPE) + set(${_channel_prefix}_CLIENT_ENTRY ${${_channel_prefix}_CLIENT_ENTRY} PARENT_SCOPE) + set(CHANNEL_STATIC_CLIENT_ENTRIES ${CHANNEL_STATIC_CLIENT_ENTRIES} ${${_channel_prefix}_CLIENT_ENTRY} PARENT_SCOPE) + endif() + endif() endmacro(add_channel_client) macro(add_channel_server _channel_prefix _channel_name) - add_subdirectory(server) - if(${${_channel_prefix}_SERVER_STATIC}) - set(CHANNEL_STATIC_SERVER_MODULES ${CHANNEL_STATIC_SERVER_MODULES} ${_channel_prefix} PARENT_SCOPE) - set(${_channel_prefix}_SERVER_NAME ${${_channel_prefix}_SERVER_NAME} PARENT_SCOPE) - set(${_channel_prefix}_SERVER_CHANNEL ${${_channel_prefix}_SERVER_CHANNEL} PARENT_SCOPE) - set(${_channel_prefix}_SERVER_ENTRY ${${_channel_prefix}_SERVER_ENTRY} PARENT_SCOPE) - set(CHANNEL_STATIC_SERVER_ENTRIES ${CHANNEL_STATIC_SERVER_ENTRIES} ${${_channel_prefix}_SERVER_ENTRY} PARENT_SCOPE) - endif() + if (${_channel_prefix}_SERVER) + add_subdirectory(server) + if(${${_channel_prefix}_SERVER_STATIC}) + set(CHANNEL_STATIC_SERVER_MODULES ${CHANNEL_STATIC_SERVER_MODULES} ${_channel_prefix} PARENT_SCOPE) + set(${_channel_prefix}_SERVER_NAME ${${_channel_prefix}_SERVER_NAME} PARENT_SCOPE) + set(${_channel_prefix}_SERVER_CHANNEL ${${_channel_prefix}_SERVER_CHANNEL} PARENT_SCOPE) + set(${_channel_prefix}_SERVER_ENTRY ${${_channel_prefix}_SERVER_ENTRY} PARENT_SCOPE) + set(CHANNEL_STATIC_SERVER_ENTRIES ${CHANNEL_STATIC_SERVER_ENTRIES} ${${_channel_prefix}_SERVER_ENTRY} PARENT_SCOPE) + endif() + endif() endmacro(add_channel_server) macro(add_channel_client_subsystem _channel_prefix _channel_name _subsystem _type) diff --git a/channels/disp/ChannelOptions.cmake b/channels/disp/ChannelOptions.cmake index 0e254adad..121f555ce 100644 --- a/channels/disp/ChannelOptions.cmake +++ b/channels/disp/ChannelOptions.cmake @@ -1,7 +1,7 @@ set(OPTION_DEFAULT OFF) set(OPTION_CLIENT_DEFAULT ON) -set(OPTION_SERVER_DEFAULT OFF) +set(OPTION_SERVER_DEFAULT ON) define_channel_options(NAME "disp" TYPE "dynamic" DESCRIPTION "Display Update Virtual Channel Extension" diff --git a/channels/rail/ChannelOptions.cmake b/channels/rail/ChannelOptions.cmake index 76f8571f2..4284cfedb 100644 --- a/channels/rail/ChannelOptions.cmake +++ b/channels/rail/ChannelOptions.cmake @@ -1,7 +1,7 @@ set(OPTION_DEFAULT OFF) set(OPTION_CLIENT_DEFAULT ON) -set(OPTION_SERVER_DEFAULT OFF) +set(OPTION_SERVER_DEFAULT ON) define_channel_options(NAME "rail" TYPE "static" DESCRIPTION "Remote Programs Virtual Channel Extension" diff --git a/channels/rdpei/ChannelOptions.cmake b/channels/rdpei/ChannelOptions.cmake index d3f874355..61864612f 100644 --- a/channels/rdpei/ChannelOptions.cmake +++ b/channels/rdpei/ChannelOptions.cmake @@ -1,7 +1,7 @@ set(OPTION_DEFAULT OFF) set(OPTION_CLIENT_DEFAULT ON) -set(OPTION_SERVER_DEFAULT OFF) +set(OPTION_SERVER_DEFAULT ON) define_channel_options(NAME "rdpei" TYPE "dynamic" DESCRIPTION "Input Virtual Channel Extension" diff --git a/channels/rdpgfx/ChannelOptions.cmake b/channels/rdpgfx/ChannelOptions.cmake index acb8de851..f29f019da 100644 --- a/channels/rdpgfx/ChannelOptions.cmake +++ b/channels/rdpgfx/ChannelOptions.cmake @@ -1,7 +1,7 @@ set(OPTION_DEFAULT OFF) set(OPTION_CLIENT_DEFAULT ON) -set(OPTION_SERVER_DEFAULT OFF) +set(OPTION_SERVER_DEFAULT ON) define_channel_options(NAME "rdpgfx" TYPE "dynamic" DESCRIPTION "Graphics Pipeline Extension" diff --git a/checker/abi-suppr.txt b/checker/abi-suppr.txt new file mode 100644 index 000000000..98780dd1d --- /dev/null +++ b/checker/abi-suppr.txt @@ -0,0 +1,9 @@ +# settings are opaque, ignore all changes +[suppress_type] +type_kind = struct +name = rdp_settings + +# allow insertions at end of structs +[suppress_type] +type_kind = struct +has_data_members_inserted_at = end diff --git a/checker/check-abi b/checker/check-abi new file mode 100755 index 000000000..aa00a13c4 --- /dev/null +++ b/checker/check-abi @@ -0,0 +1,282 @@ +#!/usr/bin/python3 + +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Copyright 2019 Mathieu Bridon +# Copyright 2021 Bastien Nocera + +"""check-abi""" + +import argparse +import contextlib +import glob +import os +import shutil +import subprocess +import sys + +VERSION = '0.1' + +def format_title(title): + """Put title in a box""" + box = { + 'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║', + } + hline = box['h'] * (len(title) + 2) + + return '\n'.join([ + f"{box['tl']}{hline}{box['tr']}", + f"{box['v']} {title} {box['v']}", + f"{box['bl']}{hline}{box['br']}", + ]) + + +def rm_rf(path): + """rm -rf""" + try: + shutil.rmtree(path) + except FileNotFoundError: + pass + + +def sanitize_path(name): + """Replace slashes with dashes""" + return name.replace('/', '-') + + +def get_current_revision(): + """gets the current git revision""" + revision = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], + encoding='utf-8').strip() + + if revision == 'HEAD': + # This is a detached HEAD, get the commit hash + revision = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8') + + return revision + + +def get_meson_version(): + """Retrieves the version of Meson as a tuple""" + res = subprocess.check_output(['meson', '--version']).strip().decode('utf-8') + return [int(x) for x in res.split('.')] + + +def build_meson(build_dir, parameters, env): + """Builds using Meson""" + _setup_args = ['meson', 'setup', build_dir, '--prefix=/usr', '--libdir=lib'] + meson_version = get_meson_version() + if meson_version[0] > 0 or (meson_version[0] == 0 and meson_version[1] >= 54): + _compile_args = ['meson', 'compile', '-v', '-C', build_dir] + else: + _compile_args = ['ninja', '-v', '-C', build_dir] + if meson_version[0] > 0 or (meson_version[0] == 0 and meson_version[1] >= 47): + _install_args = ['meson', 'install', '-C', build_dir] + else: + _install_args = ['ninja', '-v', '-C', build_dir, 'install'] + if parameters is not None: + _setup_args += parameters.split(' ') + subprocess.check_call(_setup_args) + subprocess.check_call(_compile_args) + subprocess.check_call(_install_args, env=env) + + +def get_cmake_version(): + """Retrieves the version of CMake as a tuple""" + res = subprocess.check_output(['cmake', '--version']).strip().decode('utf-8') + lines = res.split('\n') + ver = lines[0].replace('cmake version ', '') + return [int(x) for x in ver.split('.')] + + +def build_cmake(build_dir, parameters, env): + """Builds using CMake""" + _setup_args = [ + "cmake", + "-GNinja", + "-B", + build_dir, + "-S", + ".", + "-DCMAKE_INSTALL_PREFIX=/usr", + "-DCMAKE_INSTALL_LIBDIR=lib", + ] + _compile_args = ['cmake', '--build', build_dir] + _install_args = ['cmake', '--install', build_dir] + if parameters is not None: + _setup_args += parameters.split(' ') + subprocess.check_call(_setup_args) + subprocess.check_call(_compile_args) + subprocess.check_call(_install_args, env=env) + + +def build_autotools(revision, src_dir_copy, build_dir, parameters, env): + """Builds using Autotools""" + src_dir = os.getcwd() + + # Setup src dir copy + os.mkdir(src_dir_copy) + os.chdir(src_dir_copy) + subprocess.check_call(['git', 'clone', src_dir, '.']) + subprocess.check_call(['git', 'checkout', '-q', revision]) + subprocess.check_call(['sed', + '-i', + 's/AM_GNU_GETTEXT_VERSION.*/AM_GNU_GETTEXT_VERSION([0.21])/', + 'configure.ac']) + os.chdir('..') + + os.mkdir(build_dir) + os.chdir(build_dir) + autogen_path = src_dir_copy + '/autogen.sh' + _args = [autogen_path, '--prefix=/usr', '--libdir=/usr/lib'] + if parameters is not None: + _args += parameters.split(' ') + subprocess.check_call(_args) + subprocess.check_call(['make']) + subprocess.check_call(['make','install'], env=env) + os.chdir(src_dir) + + +@contextlib.contextmanager +def checkout_git_revision(revision): + """Checkout a git revision before reverting to the current one""" + current_revision = get_current_revision() + subprocess.check_call(['git', 'checkout', '-q', revision]) + + try: + yield + finally: + subprocess.check_call(['git', 'checkout', '-q', current_revision]) + + +def build_install(revision, build_system, parameters): + """Build git revision with the passed build system""" + build_dir = '_check_abi_build' + dest_dir = os.path.abspath(sanitize_path(revision)) + src_dir_copy = os.getcwd() + '/_src_copy' + if not args.quiet: + print(format_title(f'# Building and installing {revision} in {dest_dir}'), + end='\n\n', flush=True) + + with checkout_git_revision(revision): + rm_rf(build_dir) + rm_rf(revision) + rm_rf(src_dir_copy) + + env = os.environ.copy() + env['DESTDIR'] = dest_dir + env['V'] = '1' + + if not build_system or build_system == 'autodetect': + if os.path.exists('meson.build'): + build_system = 'meson' + elif os.path.exists('CMakeLists.txt'): + build_system = 'cmake' + elif os.path.exists('configure.ac') and os.path.exists('autogen.sh'): + build_system = 'autotools' + else: + print('Could not detect build system', file=sys.stderr) + assert() + + if build_system == 'meson': + build_meson(build_dir, parameters, env) + elif build_system == 'cmake': + build_cmake(build_dir, parameters, env) + elif build_system == 'autotools': + build_autotools(revision, src_dir_copy, build_dir, parameters, env) + else: + print(f'Unsupported build system "f{build_system}"', file=sys.stderr) + assert() + + return dest_dir + + +def compare(_old_tree, _new_tree): + """Compare the ABIs between 2 build trees""" + if not args.quiet: + print(format_title('# Comparing the two ABIs'), end='\n\n', flush=True) + + if not args.library_name: + paths = glob.glob(os.path.join(_old_tree, 'usr', 'lib') + '/*.so') + libs_name = [] + for path in paths: + libs_name.append(os.path.basename(path)) + else: + libs_name = [ args.library_name ] + + for lib_name in libs_name: + + old_headers = os.path.join(_old_tree, 'usr', 'include') + old_lib = os.path.join(_old_tree, 'usr', 'lib', lib_name) + + new_headers = os.path.join(_new_tree, 'usr', 'include') + new_lib = os.path.join(_new_tree, 'usr', 'lib', lib_name) + + cmd = [ + 'abidiff', '--headers-dir1', old_headers, '--headers-dir2', new_headers, + '--drop-private-types', '--fail-no-debug-info', '--no-added-syms' + ] + if args.suppr: + cmd.append ('--suppr') + cmd.append (args.suppr) + + cmd.append (old_lib) + cmd.append (new_lib) + + subprocess.check_call(cmd) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument('old', help='the previous git revision, considered the reference') + parser.add_argument('new', help='the new git revision, to compare to the reference') + parser.add_argument('-q', '--quiet', action='store_true', help='increase output verbosity') + parser.add_argument('-s', '--suppr', help='Pass a suppression file to abidiff') + parser.add_argument('--old-build-system', + help='build system to use for the reference git revision (default: autodetect)', + type=str, choices=['autodetect', 'meson', 'cmake', 'autotools']) + parser.add_argument('--new-build-system', + help='build system to use for the new git revision (default: autodetect)', + type=str, choices=['autodetect', 'meson', 'cmake', 'autotools']) + parser.add_argument('--old-parameters', + help='additional arguments to pass to the reference git revisionʼs build system', + type=str) + parser.add_argument('--new-parameters', + help='additional arguments to pass to the new git revisionʼs build system', + type=str) + parser.add_argument('--parameters', + help="additional arguments to pass to both the old and the" + " new git revisionʼs build systems", + type=str) + parser.add_argument('-l', '--library-name', + help='the name of the shared library to compare (default: \'*.so\')', + type=str) + + args = parser.parse_args() + + if args.parameters: + if args.old_parameters or args.new_parameters: + if not args.quiet: + print("Can't pass --parameters with either --old-parameters" + " or --new-parameters") + sys.exit(1) + args.old_parameters = args.parameters + args.new_parameters = args.parameters + + if args.old == args.new and args.old_parameters == args.new_parameters: + if not args.quiet: + print("Let's not waste time comparing something to itself") + sys.exit(0) + + old_tree = build_install(args.old, args.old_build_system, args.old_parameters) + new_tree = build_install(args.new, args.new_build_system, args.new_parameters) + + try: + compare(old_tree, new_tree) + + except Exception: # pylint: disable=broad-except + sys.exit(1) + + if not args.quiet: + print(f'Hurray! {args.old} and {args.new} are ABI-compatible!') \ No newline at end of file