diff --git a/docs/yaml/functions/include_directories.yaml b/docs/yaml/functions/include_directories.yaml index 77faeb4f3caf..d93538a623b2 100644 --- a/docs/yaml/functions/include_directories.yaml +++ b/docs/yaml/functions/include_directories.yaml @@ -19,6 +19,21 @@ description: | Each directory given is converted to two include paths: one that is relative to the source root and one relative to the build root. +warnings: + - | + Before 1.11.0, when `is_system : true` was used with multiple + directories, the include directory order on the command line was + **reversed** compared to the order given in the arguments: the + *last* directory listed had the highest priority (it appeared first + among the `-isystem` flags and was searched first by the compiler). + This was the opposite of the default (`is_system : false`), where + the *first* directory listed has the highest priority. + + Starting from 1.11.0, the order is consistent: the first directory + listed always has the highest priority, regardless of `is_system`. + Projects that do not set `meson_version` to 1.11.0 or newer will + keep the old reversed behaviour. + example: | For example, with the following source tree layout in `/home/user/project.git`: diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 7a65d8d26193..5425c4aab9a3 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -48,7 +48,13 @@ \.a$''', re.X) class CLikeCompilerArgs(arglist.CompilerArgs): - prepend_prefixes = ('-I', '-L') + # ``-isystem`` was added to prepend_prefixes in 1.11.0. Before that, + # it was only in dedup2_prefixes, which caused the ninja backend's + # reversed include-directory loop to produce a reversed command-line + # order for ``-isystem`` flags. func_include_directories() in the + # interpreter has a backwards-compatibility shim that reverses the + # directory list for projects with meson_version < 1.11.0. + prepend_prefixes = ('-I', '-isystem', '-L') dedup2_prefixes = ('-I', '-isystem', '-L', '-D', '-U') # NOTE: not thorough. A list of potential corner cases can be found in diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index ff37de920f68..6e8cc9db335c 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -28,7 +28,7 @@ from ..interpreterbase import noPosargs, noKwargs, permittedKwargs, noArgsFlattening, noSecondLevelHolderResolving, unholder_return from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest from ..interpreterbase import Disabler, disablerIfNotFound -from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureNewKwargs +from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureFixed, FeatureNewKwargs from ..interpreterbase import ObjectHolder, ContextManagerObject from ..interpreterbase import stringifyUserArguments from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule @@ -2849,7 +2849,25 @@ def extract_incdirs(self, prospectives: T.List[T.Union[str, build.IncludeDirs]], @typed_kwargs('include_directories', KwargInfo('is_system', bool, default=False)) def func_include_directories(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]], kwargs: 'kwtypes.FuncIncludeDirectories') -> build.IncludeDirs: - return self.build_incdir_object(args[0], kwargs['is_system']) + dirs = args[0] + if kwargs['is_system'] and len(dirs) > 1: + FeatureFixed.single_use( + 'include_directories with is_system:true and more than one path', '1.11.0', + self.subproject, + 'The search order of system include directories was previously reversed ' + 'compared to non-system includes (last listed directory was searched first). ' + 'Starting from 1.11.0, the order is the same as for non-system includes. ' + 'Use separate include_directories() calls or require Meson version >= 1.11.0.', + node) + # For backwards compatibility, reverse the directory list so + # that projects written for the old behaviour (last-listed = + # highest priority) continue to work. Projects that set + # meson_version >= 1.11.0 get the corrected order (first-listed = + # highest priority), matching non-system includes. + pv = mesonlib.project_meson_versions.get(self.subproject, '') + if not isinstance(pv, str) or not mesonlib.version_compare(pv, '>=1.11.0'): + dirs = list(reversed(dirs)) + return self.build_incdir_object(dirs, kwargs['is_system']) def build_incdir_object(self, incdir_strings: T.List[str], is_system: bool = False) -> build.IncludeDirs: if not isinstance(is_system, bool): @@ -3097,6 +3115,7 @@ def run(self) -> None: FeatureNew.report(self.subproject) FeatureDeprecated.report(self.subproject) FeatureBroken.report(self.subproject) + FeatureFixed.report(self.subproject) if not self.is_subproject(): self.print_extra_warnings() self._print_summary() diff --git a/mesonbuild/interpreterbase/__init__.py b/mesonbuild/interpreterbase/__init__.py index 88fa706b9e90..6b72f0c8a4e0 100644 --- a/mesonbuild/interpreterbase/__init__.py +++ b/mesonbuild/interpreterbase/__init__.py @@ -42,6 +42,7 @@ 'FeatureNew', 'FeatureDeprecated', 'FeatureBroken', + 'FeatureFixed', 'FeatureNewKwargs', 'FeatureDeprecatedKwargs', @@ -106,6 +107,7 @@ FeatureNew, FeatureDeprecated, FeatureBroken, + FeatureFixed, FeatureNewKwargs, FeatureDeprecatedKwargs, ) diff --git a/mesonbuild/interpreterbase/decorators.py b/mesonbuild/interpreterbase/decorators.py index 967892e30225..c42003ba8918 100644 --- a/mesonbuild/interpreterbase/decorators.py +++ b/mesonbuild/interpreterbase/decorators.py @@ -821,6 +821,39 @@ def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], locatio mlog.deprecation(*args, location=location) +class FeatureFixed(FeatureCheckBase): + """Checks for features that were always broken but have been fixed.""" + + # Class variable, shared across all instances + # + # Format: {subproject: {feature_version: set(feature_names)}} + feature_registry = {} + unconditional = True + + @staticmethod + def check_version(target_version: T.Union[str, mesonlib.NoProjectVersion], feature_version: str) -> bool: + return FeatureNew.check_version(target_version, feature_version) + + @staticmethod + def get_warning_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: + return 'Fixed features used:' + + @staticmethod + def get_notice_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: + return '' + + def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], location: T.Optional['mparser.BaseNode']) -> None: + args = [ + 'Project uses feature that was always broken,', + 'though it has been fixed since', + f"'{self.feature_version}':", + f'{self.feature_name}.', + ] + if self.extra_message: + args.append(self.extra_message) + mlog.warning(*args, location=location) + + # This cannot be a dataclass due to https://github.com/python/mypy/issues/5374 class FeatureCheckKwargsBase(metaclass=abc.ABCMeta): diff --git a/test cases/common/290 systemd regression/keyctl.c b/test cases/common/290 systemd regression/keyctl.c new file mode 100644 index 000000000000..96498ff92f04 --- /dev/null +++ b/test cases/common/290 systemd regression/keyctl.c @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include diff --git a/test cases/common/290 systemd regression/meson.build b/test cases/common/290 systemd regression/meson.build new file mode 100644 index 000000000000..f3a13516ccff --- /dev/null +++ b/test cases/common/290 systemd regression/meson.build @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +project('test', 'c', meson_version: '>=0.62.0', version: '1.0', default_options: [ 'c_std=gnu17', ]) + +if host_machine.system() != 'linux' + error('MESON_SKIP_TEST: systemd include ordering regression test needs Linux') +endif + +conf = configuration_data() +config_h = configure_file(output : 'config.h', configuration : conf) +userspace = declare_dependency(compile_args : ['-include', 'config.h']) + +system_includes = [ + include_directories( + # gcc(1) says + # "Directories specified with -isystem options are scanned in left-to-right order", + # and meson puts the directories in the reversed order. Hence, a directory with a lower + # priority must be listed earlier. + 'uapi', + 'override', + is_system : true, + ), +] + +static_library( + 'c-wrapper', + files('keyctl.c'), + include_directories : system_includes, + implicit_include_directories : false, + dependencies : [userspace], + c_args : ['-fvisibility=default'], + build_by_default : true) diff --git a/test cases/common/290 systemd regression/override/linux/keyctl.h b/test cases/common/290 systemd regression/override/linux/keyctl.h new file mode 100644 index 000000000000..4a2a00d8d349 --- /dev/null +++ b/test cases/common/290 systemd regression/override/linux/keyctl.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#if 0 // removed for meson testsuite +#include_next /* IWYU pragma: export */ +#endif + +#include + +/* From linux/key.h */ +#ifndef KEY_POS_VIEW + +typedef int32_t key_serial_t; + +# define KEY_POS_VIEW 0x01000000 +# define KEY_POS_READ 0x02000000 +# define KEY_POS_WRITE 0x04000000 +# define KEY_POS_SEARCH 0x08000000 +# define KEY_POS_LINK 0x10000000 +# define KEY_POS_SETATTR 0x20000000 +# define KEY_POS_ALL 0x3f000000 + +# define KEY_USR_VIEW 0x00010000 +# define KEY_USR_READ 0x00020000 +# define KEY_USR_WRITE 0x00040000 +# define KEY_USR_SEARCH 0x00080000 +# define KEY_USR_LINK 0x00100000 +# define KEY_USR_SETATTR 0x00200000 +# define KEY_USR_ALL 0x003f0000 + +# define KEY_GRP_VIEW 0x00000100 +# define KEY_GRP_READ 0x00000200 +# define KEY_GRP_WRITE 0x00000400 +# define KEY_GRP_SEARCH 0x00000800 +# define KEY_GRP_LINK 0x00001000 +# define KEY_GRP_SETATTR 0x00002000 +# define KEY_GRP_ALL 0x00003f00 + +# define KEY_OTH_VIEW 0x00000001 +# define KEY_OTH_READ 0x00000002 +# define KEY_OTH_WRITE 0x00000004 +# define KEY_OTH_SEARCH 0x00000008 +# define KEY_OTH_LINK 0x00000010 +# define KEY_OTH_SETATTR 0x00000020 +# define KEY_OTH_ALL 0x0000003f +#else +static_assert(KEY_OTH_ALL == 0x0000003f, ""); +#endif diff --git a/test cases/common/290 systemd regression/override/sys/keyctl.h b/test cases/common/290 systemd regression/override/sys/keyctl.h new file mode 100644 index 000000000000..88c9c40ea78b --- /dev/null +++ b/test cases/common/290 systemd regression/override/sys/keyctl.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include /* IWYU pragma: export */ +#include + +#if !HAVE_KEYCTL +long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); +# define keyctl missing_keyctl +#endif + +#if !HAVE_ADD_KEY +key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid); +# define add_key missing_add_key +#endif + +#if !HAVE_REQUEST_KEY +key_serial_t missing_request_key(const char *type, const char *description, const char *callout_info, key_serial_t destringid); +# define request_key missing_request_key +#endif diff --git a/test cases/common/290 systemd regression/test.json b/test cases/common/290 systemd regression/test.json new file mode 100644 index 000000000000..d40278dc165a --- /dev/null +++ b/test cases/common/290 systemd regression/test.json @@ -0,0 +1,8 @@ +{ + "stdout": [ + { + "line": "test cases/common/290 systemd regression/meson.build:14: WARNING: Project uses feature that was always broken, though it has been fixed since '1.11.0': include_directories with is_system:true and more than one path. The search order of system include directories was previously reversed compared to non-system includes (last listed directory was searched first). Starting from 1.11.0, the order is the same as for non-system includes. Use separate include_directories() calls or require Meson version >= 1.11.0." + } + ], + "expect_skip_on_jobname": ["azure", "cygwin", "macos", "msys2", "windows"] +} diff --git a/test cases/common/290 systemd regression/uapi/linux/keyctl.h b/test cases/common/290 systemd regression/uapi/linux/keyctl.h new file mode 100644 index 000000000000..222c6c688ad1 --- /dev/null +++ b/test cases/common/290 systemd regression/uapi/linux/keyctl.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* keyctl.h: keyctl command IDs + * + * Copyright (C) 2004, 2008 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _LINUX_KEYCTL_H +#define _LINUX_KEYCTL_H + +#include + +/* special process keyring shortcut IDs */ +#define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */ +#define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */ +#define KEY_SPEC_SESSION_KEYRING -3 /* - key ID for session-specific keyring */ +#define KEY_SPEC_USER_KEYRING -4 /* - key ID for UID-specific keyring */ +#define KEY_SPEC_USER_SESSION_KEYRING -5 /* - key ID for UID-session keyring */ +#define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */ +#define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */ +#define KEY_SPEC_REQUESTOR_KEYRING -8 /* - key ID for request_key() dest keyring */ + +/* request-key default keyrings */ +#define KEY_REQKEY_DEFL_NO_CHANGE -1 +#define KEY_REQKEY_DEFL_DEFAULT 0 +#define KEY_REQKEY_DEFL_THREAD_KEYRING 1 +#define KEY_REQKEY_DEFL_PROCESS_KEYRING 2 +#define KEY_REQKEY_DEFL_SESSION_KEYRING 3 +#define KEY_REQKEY_DEFL_USER_KEYRING 4 +#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5 +#define KEY_REQKEY_DEFL_GROUP_KEYRING 6 +#define KEY_REQKEY_DEFL_REQUESTOR_KEYRING 7 + +/* keyctl commands */ +#define KEYCTL_GET_KEYRING_ID 0 /* ask for a keyring's ID */ +#define KEYCTL_JOIN_SESSION_KEYRING 1 /* join or start named session keyring */ +#define KEYCTL_UPDATE 2 /* update a key */ +#define KEYCTL_REVOKE 3 /* revoke a key */ +#define KEYCTL_CHOWN 4 /* set ownership of a key */ +#define KEYCTL_SETPERM 5 /* set perms on a key */ +#define KEYCTL_DESCRIBE 6 /* describe a key */ +#define KEYCTL_CLEAR 7 /* clear contents of a keyring */ +#define KEYCTL_LINK 8 /* link a key into a keyring */ +#define KEYCTL_UNLINK 9 /* unlink a key from a keyring */ +#define KEYCTL_SEARCH 10 /* search for a key in a keyring */ +#define KEYCTL_READ 11 /* read a key or keyring's contents */ +#define KEYCTL_INSTANTIATE 12 /* instantiate a partially constructed key */ +#define KEYCTL_NEGATE 13 /* negate a partially constructed key */ +#define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */ +#define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ +#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ +#define KEYCTL_GET_SECURITY 17 /* get key security label */ +#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ +#define KEYCTL_REJECT 19 /* reject a partially constructed key */ +#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ +#define KEYCTL_INVALIDATE 21 /* invalidate a key */ +#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ +#define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */ +#define KEYCTL_PKEY_QUERY 24 /* Query public key parameters */ +#define KEYCTL_PKEY_ENCRYPT 25 /* Encrypt a blob using a public key */ +#define KEYCTL_PKEY_DECRYPT 26 /* Decrypt a blob using a public key */ +#define KEYCTL_PKEY_SIGN 27 /* Create a public key signature */ +#define KEYCTL_PKEY_VERIFY 28 /* Verify a public key signature */ +#define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */ +#define KEYCTL_MOVE 30 /* Move keys between keyrings */ +#define KEYCTL_CAPABILITIES 31 /* Find capabilities of keyrings subsystem */ +#define KEYCTL_WATCH_KEY 32 /* Watch a key or ring of keys for changes */ + +/* keyctl structures */ +struct keyctl_dh_params { + union { +#ifndef __cplusplus + __s32 private; +#endif + __s32 priv; + }; + __s32 prime; + __s32 base; +}; + +struct keyctl_kdf_params { + char *hashname; + char *otherinfo; + __u32 otherinfolen; + __u32 __spare[8]; +}; + +#define KEYCTL_SUPPORTS_ENCRYPT 0x01 +#define KEYCTL_SUPPORTS_DECRYPT 0x02 +#define KEYCTL_SUPPORTS_SIGN 0x04 +#define KEYCTL_SUPPORTS_VERIFY 0x08 + +struct keyctl_pkey_query { + __u32 supported_ops; /* Which ops are supported */ + __u32 key_size; /* Size of the key in bits */ + __u16 max_data_size; /* Maximum size of raw data to sign in bytes */ + __u16 max_sig_size; /* Maximum size of signature in bytes */ + __u16 max_enc_size; /* Maximum size of encrypted blob in bytes */ + __u16 max_dec_size; /* Maximum size of decrypted blob in bytes */ + __u32 __spare[10]; +}; + +struct keyctl_pkey_params { + __s32 key_id; /* Serial no. of public key to use */ + __u32 in_len; /* Input data size */ + union { + __u32 out_len; /* Output buffer size (encrypt/decrypt/sign) */ + __u32 in2_len; /* 2nd input data size (verify) */ + }; + __u32 __spare[7]; +}; + +#define KEYCTL_MOVE_EXCL 0x00000001 /* Do not displace from the to-keyring */ + +/* + * Capabilities flags. The capabilities list is an array of 8-bit integers; + * each integer can carry up to 8 flags. + */ +#define KEYCTL_CAPS0_CAPABILITIES 0x01 /* KEYCTL_CAPABILITIES supported */ +#define KEYCTL_CAPS0_PERSISTENT_KEYRINGS 0x02 /* Persistent keyrings enabled */ +#define KEYCTL_CAPS0_DIFFIE_HELLMAN 0x04 /* Diffie-Hellman computation enabled */ +#define KEYCTL_CAPS0_PUBLIC_KEY 0x08 /* Public key ops enabled */ +#define KEYCTL_CAPS0_BIG_KEY 0x10 /* big_key-type enabled */ +#define KEYCTL_CAPS0_INVALIDATE 0x20 /* KEYCTL_INVALIDATE supported */ +#define KEYCTL_CAPS0_RESTRICT_KEYRING 0x40 /* KEYCTL_RESTRICT_KEYRING supported */ +#define KEYCTL_CAPS0_MOVE 0x80 /* KEYCTL_MOVE supported */ +#define KEYCTL_CAPS1_NS_KEYRING_NAME 0x01 /* Keyring names are per-user_namespace */ +#define KEYCTL_CAPS1_NS_KEY_TAG 0x02 /* Key indexing can include a namespace tag */ +#define KEYCTL_CAPS1_NOTIFICATIONS 0x04 /* Keys generate watchable notifications */ + +#endif /* _LINUX_KEYCTL_H */