mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-27 16:23:32 +00:00
Kbuild updates for v6.13
- Add generic support for built-in boot DTB files - Enable TAB cycling for dialog buttons in nconfig - Fix issues in streamline_config.pl - Refactor Kconfig - Add support for Clang's AutoFDO (Automatic Feedback-Directed Optimization) - Add support for Clang's Propeller, a profile-guided optimization. - Change the working directory to the external module directory for M= builds - Support building external modules in a separate output directory - Enable objtool for *.mod.o and additional kernel objects - Use lz4 instead of deprecated lz4c - Work around a performance issue with "git describe" - Refactor modpost -----BEGIN PGP SIGNATURE----- iQJJBAABCgAzFiEEbmPs18K1szRHjPqEPYsBB53g2wYFAmdKGgEVHG1hc2FoaXJv eUBrZXJuZWwub3JnAAoJED2LAQed4NsGrFoQAIgioJPRG+HC6bGmjy4tL4bq1RAm 78nbD12grrAa+NvQGRZYRs264rWxBGwrNfGGS9BDvlWJZ3fmKEuPlfCIxC0nkKk8 LVLNxSVvgpHE47RQ+E4V+yYhrlZKb4aWZjH3ZICn7vxRgbQ5Veq61aatluVHyn9c I8g+APYN/S1A4JkFzaLe8GV7v5OM3+zGSn3M9n7/DxVkoiNrMOXJm5hRdRgYfEv/ kMppheY2PPshZsaL+yLAdrJccY5au5vYE/v8wHkMtvM/LF6YwjgqPVDRFQ30BuLM sAMMd6AUoopiDZQOpqmXYukU0b0MQPswg3jmB+PWUBrlsuydRa8kkyPwUaFrDd+w 9d0jZRc8/O/lxUdD1AefRkNcA/dIJ4lTPr+2NpxwHuj2UFo0gLQmtjBggMFHaWvs 0NQRBPlxfOE4+Htl09gyg230kHuWq+rh7xqbyJCX+hBOaZ6kI2lryl6QkgpAoS+x KDOcUKnsgGMGARQRrvCOAXnQs+rjkW8fEm6t7eSBFPuWJMK85k4LmxOog8GVYEdM JcwCnCHt9TtcHlSxLRnVXj2aqGTFNLJXE1aLyCp9u8MxZ7qcx01xOuCmwp6FRzNq ghal7ngA58Y/S4K/oJ+CW2KupOb6CFne8mpyotpYeWI7MR64t0YWs4voZkuK46E2 CEBfA4PDehA4BxQe =GDKD -----END PGP SIGNATURE----- Merge tag 'kbuild-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild Pull Kbuild updates from Masahiro Yamada: - Add generic support for built-in boot DTB files - Enable TAB cycling for dialog buttons in nconfig - Fix issues in streamline_config.pl - Refactor Kconfig - Add support for Clang's AutoFDO (Automatic Feedback-Directed Optimization) - Add support for Clang's Propeller, a profile-guided optimization. - Change the working directory to the external module directory for M= builds - Support building external modules in a separate output directory - Enable objtool for *.mod.o and additional kernel objects - Use lz4 instead of deprecated lz4c - Work around a performance issue with "git describe" - Refactor modpost * tag 'kbuild-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild: (85 commits) kbuild: rename .tmp_vmlinux.kallsyms0.syms to .tmp_vmlinux0.syms gitignore: Don't ignore 'tags' directory kbuild: add dependency from vmlinux to resolve_btfids modpost: replace tdb_hash() with hash_str() kbuild: deb-pkg: add python3:native to build dependency genksyms: reduce indentation in export_symbol() modpost: improve error messages in device_id_check() modpost: rename alias symbol for MODULE_DEVICE_TABLE() modpost: rename variables in handle_moddevtable() modpost: move strstarts() to modpost.h modpost: convert do_usb_table() to a generic handler modpost: convert do_of_table() to a generic handler modpost: convert do_pnp_device_entry() to a generic handler modpost: convert do_pnp_card_entries() to a generic handler modpost: call module_alias_printf() from all do_*_entry() functions modpost: pass (struct module *) to do_*_entry() functions modpost: remove DEF_FIELD_ADDR_VAR() macro modpost: deduplicate MODULE_ALIAS() for all drivers modpost: introduce module_alias_printf() helper modpost: remove unnecessary check in do_acpi_entry() ...
This commit is contained in:
commit
6a34dfa15d
1
.gitignore
vendored
1
.gitignore
vendored
@ -129,6 +129,7 @@ series
|
||||
|
||||
# ctags files
|
||||
tags
|
||||
!tags/
|
||||
TAGS
|
||||
|
||||
# cscope files
|
||||
|
168
Documentation/dev-tools/autofdo.rst
Normal file
168
Documentation/dev-tools/autofdo.rst
Normal file
@ -0,0 +1,168 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===================================
|
||||
Using AutoFDO with the Linux kernel
|
||||
===================================
|
||||
|
||||
This enables AutoFDO build support for the kernel when using
|
||||
the Clang compiler. AutoFDO (Auto-Feedback-Directed Optimization)
|
||||
is a type of profile-guided optimization (PGO) used to enhance the
|
||||
performance of binary executables. It gathers information about the
|
||||
frequency of execution of various code paths within a binary using
|
||||
hardware sampling. This data is then used to guide the compiler's
|
||||
optimization decisions, resulting in a more efficient binary. AutoFDO
|
||||
is a powerful optimization technique, and data indicates that it can
|
||||
significantly improve kernel performance. It's especially beneficial
|
||||
for workloads affected by front-end stalls.
|
||||
|
||||
For AutoFDO builds, unlike non-FDO builds, the user must supply a
|
||||
profile. Acquiring an AutoFDO profile can be done in several ways.
|
||||
AutoFDO profiles are created by converting hardware sampling using
|
||||
the "perf" tool. It is crucial that the workload used to create these
|
||||
perf files is representative; they must exhibit runtime
|
||||
characteristics similar to the workloads that are intended to be
|
||||
optimized. Failure to do so will result in the compiler optimizing
|
||||
for the wrong objective.
|
||||
|
||||
The AutoFDO profile often encapsulates the program's behavior. If the
|
||||
performance-critical codes are architecture-independent, the profile
|
||||
can be applied across platforms to achieve performance gains. For
|
||||
instance, using the profile generated on Intel architecture to build
|
||||
a kernel for AMD architecture can also yield performance improvements.
|
||||
|
||||
There are two methods for acquiring a representative profile:
|
||||
(1) Sample real workloads using a production environment.
|
||||
(2) Generate the profile using a representative load test.
|
||||
When enabling the AutoFDO build configuration without providing an
|
||||
AutoFDO profile, the compiler only modifies the dwarf information in
|
||||
the kernel without impacting runtime performance. It's advisable to
|
||||
use a kernel binary built with the same AutoFDO configuration to
|
||||
collect the perf profile. While it's possible to use a kernel built
|
||||
with different options, it may result in inferior performance.
|
||||
|
||||
One can collect profiles using AutoFDO build for the previous kernel.
|
||||
AutoFDO employs relative line numbers to match the profiles, offering
|
||||
some tolerance for source changes. This mode is commonly used in a
|
||||
production environment for profile collection.
|
||||
|
||||
In a profile collection based on a load test, the AutoFDO collection
|
||||
process consists of the following steps:
|
||||
|
||||
#. Initial build: The kernel is built with AutoFDO options
|
||||
without a profile.
|
||||
|
||||
#. Profiling: The above kernel is then run with a representative
|
||||
workload to gather execution frequency data. This data is
|
||||
collected using hardware sampling, via perf. AutoFDO is most
|
||||
effective on platforms supporting advanced PMU features like
|
||||
LBR on Intel machines.
|
||||
|
||||
#. AutoFDO profile generation: Perf output file is converted to
|
||||
the AutoFDO profile via offline tools.
|
||||
|
||||
The support requires a Clang compiler LLVM 17 or later.
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
Configure the kernel with::
|
||||
|
||||
CONFIG_AUTOFDO_CLANG=y
|
||||
|
||||
Customization
|
||||
=============
|
||||
|
||||
The default CONFIG_AUTOFDO_CLANG setting covers kernel space objects for
|
||||
AutoFDO builds. One can, however, enable or disable AutoFDO build for
|
||||
individual files and directories by adding a line similar to the following
|
||||
to the respective kernel Makefile:
|
||||
|
||||
- For enabling a single file (e.g. foo.o) ::
|
||||
|
||||
AUTOFDO_PROFILE_foo.o := y
|
||||
|
||||
- For enabling all files in one directory ::
|
||||
|
||||
AUTOFDO_PROFILE := y
|
||||
|
||||
- For disabling one file ::
|
||||
|
||||
AUTOFDO_PROFILE_foo.o := n
|
||||
|
||||
- For disabling all files in one directory ::
|
||||
|
||||
AUTOFDO_PROFILE := n
|
||||
|
||||
Workflow
|
||||
========
|
||||
|
||||
Here is an example workflow for AutoFDO kernel:
|
||||
|
||||
1) Build the kernel on the host machine with LLVM enabled,
|
||||
for example, ::
|
||||
|
||||
$ make menuconfig LLVM=1
|
||||
|
||||
Turn on AutoFDO build config::
|
||||
|
||||
CONFIG_AUTOFDO_CLANG=y
|
||||
|
||||
With a configuration that with LLVM enabled, use the following command::
|
||||
|
||||
$ scripts/config -e AUTOFDO_CLANG
|
||||
|
||||
After getting the config, build with ::
|
||||
|
||||
$ make LLVM=1
|
||||
|
||||
2) Install the kernel on the test machine.
|
||||
|
||||
3) Run the load tests. The '-c' option in perf specifies the sample
|
||||
event period. We suggest using a suitable prime number, like 500009,
|
||||
for this purpose.
|
||||
|
||||
- For Intel platforms::
|
||||
|
||||
$ perf record -e BR_INST_RETIRED.NEAR_TAKEN:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
|
||||
|
||||
- For AMD platforms:
|
||||
|
||||
The supported systems are: Zen3 with BRS, or Zen4 with amd_lbr_v2. To check,
|
||||
|
||||
For Zen3::
|
||||
|
||||
$ cat proc/cpuinfo | grep " brs"
|
||||
|
||||
For Zen4::
|
||||
|
||||
$ cat proc/cpuinfo | grep amd_lbr_v2
|
||||
|
||||
The following command generated the perf data file::
|
||||
|
||||
$ perf record --pfm-events RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
|
||||
|
||||
4) (Optional) Download the raw perf file to the host machine.
|
||||
|
||||
5) To generate an AutoFDO profile, two offline tools are available:
|
||||
create_llvm_prof and llvm_profgen. The create_llvm_prof tool is part
|
||||
of the AutoFDO project and can be found on GitHub
|
||||
(https://github.com/google/autofdo), version v0.30.1 or later.
|
||||
The llvm_profgen tool is included in the LLVM compiler itself. It's
|
||||
important to note that the version of llvm_profgen doesn't need to match
|
||||
the version of Clang. It needs to be the LLVM 19 release of Clang
|
||||
or later, or just from the LLVM trunk. ::
|
||||
|
||||
$ llvm-profgen --kernel --binary=<vmlinux> --perfdata=<perf_file> -o <profile_file>
|
||||
|
||||
or ::
|
||||
|
||||
$ create_llvm_prof --binary=<vmlinux> --profile=<perf_file> --format=extbinary --out=<profile_file>
|
||||
|
||||
Note that multiple AutoFDO profile files can be merged into one via::
|
||||
|
||||
$ llvm-profdata merge -o <profile_file> <profile_1> <profile_2> ... <profile_n>
|
||||
|
||||
6) Rebuild the kernel using the AutoFDO profile file with the same config as step 1,
|
||||
(Note CONFIG_AUTOFDO_CLANG needs to be enabled)::
|
||||
|
||||
$ make LLVM=1 CLANG_AUTOFDO_PROFILE=<profile_file>
|
@ -250,25 +250,17 @@ variables for .cocciconfig is as follows:
|
||||
- Your directory from which spatch is called is processed next
|
||||
- The directory provided with the ``--dir`` option is processed last, if used
|
||||
|
||||
Since coccicheck runs through make, it naturally runs from the kernel
|
||||
proper dir; as such the second rule above would be implied for picking up a
|
||||
.cocciconfig when using ``make coccicheck``.
|
||||
|
||||
``make coccicheck`` also supports using M= targets. If you do not supply
|
||||
any M= target, it is assumed you want to target the entire kernel.
|
||||
The kernel coccicheck script has::
|
||||
|
||||
if [ "$KBUILD_EXTMOD" = "" ] ; then
|
||||
OPTIONS="--dir $srctree $COCCIINCLUDE"
|
||||
else
|
||||
OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
|
||||
fi
|
||||
OPTIONS="--dir $srcroot $COCCIINCLUDE"
|
||||
|
||||
KBUILD_EXTMOD is set when an explicit target with M= is used. For both cases
|
||||
the spatch ``--dir`` argument is used, as such third rule applies when whether
|
||||
M= is used or not, and when M= is used the target directory can have its own
|
||||
.cocciconfig file. When M= is not passed as an argument to coccicheck the
|
||||
target directory is the same as the directory from where spatch was called.
|
||||
Here, $srcroot refers to the source directory of the target: it points to the
|
||||
external module's source directory when M= used, and otherwise, to the kernel
|
||||
source directory. The third rule ensures the spatch reads the .cocciconfig from
|
||||
the target directory, allowing external modules to have their own .cocciconfig
|
||||
file.
|
||||
|
||||
If not using the kernel's coccicheck target, keep the above precedence
|
||||
order logic of .cocciconfig reading. If using the kernel's coccicheck target,
|
||||
|
@ -34,6 +34,8 @@ Documentation/dev-tools/testing-overview.rst
|
||||
ktap
|
||||
checkuapi
|
||||
gpio-sloppy-logic-analyzer
|
||||
autofdo
|
||||
propeller
|
||||
|
||||
|
||||
.. only:: subproject and html
|
||||
|
162
Documentation/dev-tools/propeller.rst
Normal file
162
Documentation/dev-tools/propeller.rst
Normal file
@ -0,0 +1,162 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=====================================
|
||||
Using Propeller with the Linux kernel
|
||||
=====================================
|
||||
|
||||
This enables Propeller build support for the kernel when using Clang
|
||||
compiler. Propeller is a profile-guided optimization (PGO) method used
|
||||
to optimize binary executables. Like AutoFDO, it utilizes hardware
|
||||
sampling to gather information about the frequency of execution of
|
||||
different code paths within a binary. Unlike AutoFDO, this information
|
||||
is then used right before linking phase to optimize (among others)
|
||||
block layout within and across functions.
|
||||
|
||||
A few important notes about adopting Propeller optimization:
|
||||
|
||||
#. Although it can be used as a standalone optimization step, it is
|
||||
strongly recommended to apply Propeller on top of AutoFDO,
|
||||
AutoFDO+ThinLTO or Instrument FDO. The rest of this document
|
||||
assumes this paradigm.
|
||||
|
||||
#. Propeller uses another round of profiling on top of
|
||||
AutoFDO/AutoFDO+ThinLTO/iFDO. The whole build process involves
|
||||
"build-afdo - train-afdo - build-propeller - train-propeller -
|
||||
build-optimized".
|
||||
|
||||
#. Propeller requires LLVM 19 release or later for Clang/Clang++
|
||||
and the linker(ld.lld).
|
||||
|
||||
#. In addition to LLVM toolchain, Propeller requires a profiling
|
||||
conversion tool: https://github.com/google/autofdo with a release
|
||||
after v0.30.1: https://github.com/google/autofdo/releases/tag/v0.30.1.
|
||||
|
||||
The Propeller optimization process involves the following steps:
|
||||
|
||||
#. Initial building: Build the AutoFDO or AutoFDO+ThinLTO binary as
|
||||
you would normally do, but with a set of compile-time / link-time
|
||||
flags, so that a special metadata section is created within the
|
||||
kernel binary. The special section is only intend to be used by the
|
||||
profiling tool, it is not part of the runtime image, nor does it
|
||||
change kernel run time text sections.
|
||||
|
||||
#. Profiling: The above kernel is then run with a representative
|
||||
workload to gather execution frequency data. This data is collected
|
||||
using hardware sampling, via perf. Propeller is most effective on
|
||||
platforms supporting advanced PMU features like LBR on Intel
|
||||
machines. This step is the same as profiling the kernel for AutoFDO
|
||||
(the exact perf parameters can be different).
|
||||
|
||||
#. Propeller profile generation: Perf output file is converted to a
|
||||
pair of Propeller profiles via an offline tool.
|
||||
|
||||
#. Optimized build: Build the AutoFDO or AutoFDO+ThinLTO optimized
|
||||
binary as you would normally do, but with a compile-time /
|
||||
link-time flag to pick up the Propeller compile time and link time
|
||||
profiles. This build step uses 3 profiles - the AutoFDO profile,
|
||||
the Propeller compile-time profile and the Propeller link-time
|
||||
profile.
|
||||
|
||||
#. Deployment: The optimized kernel binary is deployed and used
|
||||
in production environments, providing improved performance
|
||||
and reduced latency.
|
||||
|
||||
Preparation
|
||||
===========
|
||||
|
||||
Configure the kernel with::
|
||||
|
||||
CONFIG_AUTOFDO_CLANG=y
|
||||
CONFIG_PROPELLER_CLANG=y
|
||||
|
||||
Customization
|
||||
=============
|
||||
|
||||
The default CONFIG_PROPELLER_CLANG setting covers kernel space objects
|
||||
for Propeller builds. One can, however, enable or disable Propeller build
|
||||
for individual files and directories by adding a line similar to the
|
||||
following to the respective kernel Makefile:
|
||||
|
||||
- For enabling a single file (e.g. foo.o)::
|
||||
|
||||
PROPELLER_PROFILE_foo.o := y
|
||||
|
||||
- For enabling all files in one directory::
|
||||
|
||||
PROPELLER_PROFILE := y
|
||||
|
||||
- For disabling one file::
|
||||
|
||||
PROPELLER_PROFILE_foo.o := n
|
||||
|
||||
- For disabling all files in one directory::
|
||||
|
||||
PROPELLER__PROFILE := n
|
||||
|
||||
|
||||
Workflow
|
||||
========
|
||||
|
||||
Here is an example workflow for building an AutoFDO+Propeller kernel:
|
||||
|
||||
1) Assuming an AutoFDO profile is already collected following
|
||||
instructions in the AutoFDO document, build the kernel on the host
|
||||
machine, with AutoFDO and Propeller build configs ::
|
||||
|
||||
CONFIG_AUTOFDO_CLANG=y
|
||||
CONFIG_PROPELLER_CLANG=y
|
||||
|
||||
and ::
|
||||
|
||||
$ make LLVM=1 CLANG_AUTOFDO_PROFILE=<autofdo-profile-name>
|
||||
|
||||
2) Install the kernel on the test machine.
|
||||
|
||||
3) Run the load tests. The '-c' option in perf specifies the sample
|
||||
event period. We suggest using a suitable prime number, like 500009,
|
||||
for this purpose.
|
||||
|
||||
- For Intel platforms::
|
||||
|
||||
$ perf record -e BR_INST_RETIRED.NEAR_TAKEN:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
|
||||
|
||||
- For AMD platforms::
|
||||
|
||||
$ perf record --pfm-event RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
|
||||
|
||||
Note you can repeat the above steps to collect multiple <perf_file>s.
|
||||
|
||||
4) (Optional) Download the raw perf file(s) to the host machine.
|
||||
|
||||
5) Use the create_llvm_prof tool (https://github.com/google/autofdo) to
|
||||
generate Propeller profile. ::
|
||||
|
||||
$ create_llvm_prof --binary=<vmlinux> --profile=<perf_file>
|
||||
--format=propeller --propeller_output_module_name
|
||||
--out=<propeller_profile_prefix>_cc_profile.txt
|
||||
--propeller_symorder=<propeller_profile_prefix>_ld_profile.txt
|
||||
|
||||
"<propeller_profile_prefix>" can be something like "/home/user/dir/any_string".
|
||||
|
||||
This command generates a pair of Propeller profiles:
|
||||
"<propeller_profile_prefix>_cc_profile.txt" and
|
||||
"<propeller_profile_prefix>_ld_profile.txt".
|
||||
|
||||
If there are more than 1 perf_file collected in the previous step,
|
||||
you can create a temp list file "<perf_file_list>" with each line
|
||||
containing one perf file name and run::
|
||||
|
||||
$ create_llvm_prof --binary=<vmlinux> --profile=@<perf_file_list>
|
||||
--format=propeller --propeller_output_module_name
|
||||
--out=<propeller_profile_prefix>_cc_profile.txt
|
||||
--propeller_symorder=<propeller_profile_prefix>_ld_profile.txt
|
||||
|
||||
6) Rebuild the kernel using the AutoFDO and Propeller
|
||||
profiles. ::
|
||||
|
||||
CONFIG_AUTOFDO_CLANG=y
|
||||
CONFIG_PROPELLER_CLANG=y
|
||||
|
||||
and ::
|
||||
|
||||
$ make LLVM=1 CLANG_AUTOFDO_PROFILE=<profile_file> CLANG_PROPELLER_PROFILE_PREFIX=<propeller_profile_prefix>
|
@ -137,12 +137,18 @@ Specify the output directory when building the kernel.
|
||||
This variable can also be used to point to the kernel output directory when
|
||||
building external modules against a pre-built kernel in a separate build
|
||||
directory. Please note that this does NOT specify the output directory for the
|
||||
external modules themselves.
|
||||
external modules themselves. (Use KBUILD_EXTMOD_OUTPUT for that purpose.)
|
||||
|
||||
The output directory can also be specified using "O=...".
|
||||
|
||||
Setting "O=..." takes precedence over KBUILD_OUTPUT.
|
||||
|
||||
KBUILD_EXTMOD_OUTPUT
|
||||
--------------------
|
||||
Specify the output directory for external modules.
|
||||
|
||||
Setting "MO=..." takes precedence over KBUILD_EXTMOD_OUTPUT.
|
||||
|
||||
KBUILD_EXTRA_WARN
|
||||
-----------------
|
||||
Specify the extra build checks. The same value can be assigned by passing
|
||||
|
@ -412,8 +412,8 @@ choices::
|
||||
<choice block>
|
||||
"endchoice"
|
||||
|
||||
This defines a choice group and accepts any of the above attributes as
|
||||
options.
|
||||
This defines a choice group and accepts "prompt", "default", "depends on", and
|
||||
"help" attributes as options.
|
||||
|
||||
A choice only allows a single config entry to be selected.
|
||||
|
||||
|
@ -449,6 +449,20 @@ $(obj)
|
||||
to prerequisites are referenced with $(src) (because they are not
|
||||
generated files).
|
||||
|
||||
$(srcroot)
|
||||
$(srcroot) refers to the root of the source you are building, which can be
|
||||
either the kernel source or the external modules source, depending on whether
|
||||
KBUILD_EXTMOD is set. This can be either a relative or an absolute path, but
|
||||
if KBUILD_ABS_SRCTREE=1 is set, it is always an absolute path.
|
||||
|
||||
$(srctree)
|
||||
$(srctree) refers to the root of the kernel source tree. When building the
|
||||
kernel, this is the same as $(srcroot).
|
||||
|
||||
$(objtree)
|
||||
$(objtree) refers to the root of the kernel object tree. It is ``.`` when
|
||||
building the kernel, but it is different when building external modules.
|
||||
|
||||
$(kecho)
|
||||
echoing information to user in a rule is often a good practice
|
||||
but when execution ``make -s`` one does not expect to see any output
|
||||
|
@ -59,6 +59,12 @@ Command Syntax
|
||||
|
||||
$ make -C /lib/modules/`uname -r`/build M=$PWD modules_install
|
||||
|
||||
Starting from Linux 6.13, you can use the -f option instead of -C. This
|
||||
will avoid unnecessary change of the working directory. The external
|
||||
module will be output to the directory where you invoke make.
|
||||
|
||||
$ make -f /lib/modules/`uname -r`/build/Makefile M=$PWD
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
@ -66,7 +72,10 @@ Options
|
||||
of the kernel output directory if the kernel was built in a separate
|
||||
build directory.)
|
||||
|
||||
make -C $KDIR M=$PWD
|
||||
You can optionally pass MO= option if you want to build the modules in
|
||||
a separate directory.
|
||||
|
||||
make -C $KDIR M=$PWD [MO=$BUILD_DIR]
|
||||
|
||||
-C $KDIR
|
||||
The directory that contains the kernel and relevant build
|
||||
@ -80,6 +89,9 @@ Options
|
||||
directory where the external module (kbuild file) is
|
||||
located.
|
||||
|
||||
MO=$BUILD_DIR
|
||||
Specifies a separate output directory for the external module.
|
||||
|
||||
Targets
|
||||
-------
|
||||
|
||||
@ -215,6 +227,21 @@ Separate Kbuild File and Makefile
|
||||
consisting of several hundred lines, and here it really pays
|
||||
off to separate the kbuild part from the rest.
|
||||
|
||||
Linux 6.13 and later support another way. The external module Makefile
|
||||
can include the kernel Makefile directly, rather than invoking sub Make.
|
||||
|
||||
Example 3::
|
||||
|
||||
--> filename: Kbuild
|
||||
obj-m := 8123.o
|
||||
8123-y := 8123_if.o 8123_pci.o
|
||||
|
||||
--> filename: Makefile
|
||||
KDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
export KBUILD_EXTMOD := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||
include $(KDIR)/Makefile
|
||||
|
||||
|
||||
Building Multiple Modules
|
||||
-------------------------
|
||||
|
||||
|
14
MAINTAINERS
14
MAINTAINERS
@ -3715,6 +3715,13 @@ F: kernel/audit*
|
||||
F: lib/*audit.c
|
||||
K: \baudit_[a-z_0-9]\+\b
|
||||
|
||||
AUTOFDO BUILD
|
||||
M: Rong Xu <xur@google.com>
|
||||
M: Han Shen <shenhan@google.com>
|
||||
S: Supported
|
||||
F: Documentation/dev-tools/autofdo.rst
|
||||
F: scripts/Makefile.autofdo
|
||||
|
||||
AUXILIARY BUS DRIVER
|
||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
R: Dave Ertman <david.m.ertman@intel.com>
|
||||
@ -18708,6 +18715,13 @@ S: Maintained
|
||||
F: include/linux/psi*
|
||||
F: kernel/sched/psi.c
|
||||
|
||||
PROPELLER BUILD
|
||||
M: Rong Xu <xur@google.com>
|
||||
M: Han Shen <shenhan@google.com>
|
||||
S: Supported
|
||||
F: Documentation/dev-tools/propeller.rst
|
||||
F: scripts/Makefile.propeller
|
||||
|
||||
PRINTK
|
||||
M: Petr Mladek <pmladek@suse.com>
|
||||
R: Steven Rostedt <rostedt@goodmis.org>
|
||||
|
221
Makefile
221
Makefile
@ -40,7 +40,7 @@ __all:
|
||||
|
||||
this-makefile := $(lastword $(MAKEFILE_LIST))
|
||||
abs_srctree := $(realpath $(dir $(this-makefile)))
|
||||
abs_objtree := $(CURDIR)
|
||||
abs_output := $(CURDIR)
|
||||
|
||||
ifneq ($(sub_make_done),1)
|
||||
|
||||
@ -134,6 +134,10 @@ ifeq ("$(origin M)", "command line")
|
||||
KBUILD_EXTMOD := $(M)
|
||||
endif
|
||||
|
||||
ifeq ("$(origin MO)", "command line")
|
||||
KBUILD_EXTMOD_OUTPUT := $(MO)
|
||||
endif
|
||||
|
||||
$(if $(word 2, $(KBUILD_EXTMOD)), \
|
||||
$(error building multiple external modules is not supported))
|
||||
|
||||
@ -176,18 +180,41 @@ export KBUILD_EXTRA_WARN
|
||||
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
|
||||
# variable.
|
||||
|
||||
# Do we want to change the working directory?
|
||||
ifeq ("$(origin O)", "command line")
|
||||
KBUILD_OUTPUT := $(O)
|
||||
endif
|
||||
|
||||
ifneq ($(KBUILD_OUTPUT),)
|
||||
ifdef KBUILD_EXTMOD
|
||||
ifdef KBUILD_OUTPUT
|
||||
objtree := $(realpath $(KBUILD_OUTPUT))
|
||||
$(if $(objtree),,$(error specified kernel directory "$(KBUILD_OUTPUT)" does not exist))
|
||||
else
|
||||
objtree := $(abs_srctree)
|
||||
endif
|
||||
# If Make is invoked from the kernel directory (either kernel
|
||||
# source directory or kernel build directory), external modules
|
||||
# are built in $(KBUILD_EXTMOD) for backward compatibility,
|
||||
# otherwise, built in the current directory.
|
||||
output := $(or $(KBUILD_EXTMOD_OUTPUT),$(if $(filter $(CURDIR),$(objtree) $(abs_srctree)),$(KBUILD_EXTMOD)))
|
||||
# KBUILD_EXTMOD might be a relative path. Remember its absolute path before
|
||||
# Make changes the working directory.
|
||||
srcroot := $(realpath $(KBUILD_EXTMOD))
|
||||
$(if $(srcroot),,$(error specified external module directory "$(KBUILD_EXTMOD)" does not exist))
|
||||
else
|
||||
objtree := .
|
||||
output := $(KBUILD_OUTPUT)
|
||||
endif
|
||||
|
||||
export objtree srcroot
|
||||
|
||||
# Do we want to change the working directory?
|
||||
ifneq ($(output),)
|
||||
# $(realpath ...) gets empty if the path does not exist. Run 'mkdir -p' first.
|
||||
$(shell mkdir -p "$(KBUILD_OUTPUT)")
|
||||
$(shell mkdir -p "$(output)")
|
||||
# $(realpath ...) resolves symlinks
|
||||
abs_objtree := $(realpath $(KBUILD_OUTPUT))
|
||||
$(if $(abs_objtree),,$(error failed to create output directory "$(KBUILD_OUTPUT)"))
|
||||
endif # ifneq ($(KBUILD_OUTPUT),)
|
||||
abs_output := $(realpath $(output))
|
||||
$(if $(abs_output),,$(error failed to create output directory "$(output)"))
|
||||
endif
|
||||
|
||||
ifneq ($(words $(subst :, ,$(abs_srctree))), 1)
|
||||
$(error source directory cannot contain spaces or colons)
|
||||
@ -197,7 +224,7 @@ export sub_make_done := 1
|
||||
|
||||
endif # sub_make_done
|
||||
|
||||
ifeq ($(abs_objtree),$(CURDIR))
|
||||
ifeq ($(abs_output),$(CURDIR))
|
||||
# Suppress "Entering directory ..." if we are at the final work directory.
|
||||
no-print-directory := --no-print-directory
|
||||
else
|
||||
@ -221,42 +248,40 @@ $(filter-out $(this-makefile), $(MAKECMDGOALS)) __all: __sub-make
|
||||
|
||||
# Invoke a second make in the output directory, passing relevant variables
|
||||
__sub-make:
|
||||
$(Q)$(MAKE) $(no-print-directory) -C $(abs_objtree) \
|
||||
$(Q)$(MAKE) $(no-print-directory) -C $(abs_output) \
|
||||
-f $(abs_srctree)/Makefile $(MAKECMDGOALS)
|
||||
|
||||
else # need-sub-make
|
||||
|
||||
# We process the rest of the Makefile if this is the final invocation of make
|
||||
|
||||
ifeq ($(abs_srctree),$(abs_objtree))
|
||||
# building in the source tree
|
||||
srctree := .
|
||||
building_out_of_srctree :=
|
||||
ifndef KBUILD_EXTMOD
|
||||
srcroot := $(abs_srctree)
|
||||
endif
|
||||
|
||||
ifeq ($(srcroot),$(CURDIR))
|
||||
building_out_of_srctree :=
|
||||
else
|
||||
ifeq ($(abs_srctree)/,$(dir $(abs_objtree)))
|
||||
# building in a subdirectory of the source tree
|
||||
srctree := ..
|
||||
else
|
||||
srctree := $(abs_srctree)
|
||||
endif
|
||||
building_out_of_srctree := 1
|
||||
export building_out_of_srctree := 1
|
||||
endif
|
||||
|
||||
ifneq ($(KBUILD_ABS_SRCTREE),)
|
||||
srctree := $(abs_srctree)
|
||||
ifdef KBUILD_ABS_SRCTREE
|
||||
# Do nothing. Use the absolute path.
|
||||
else ifeq ($(srcroot),$(CURDIR))
|
||||
# Building in the source.
|
||||
srcroot := .
|
||||
else ifeq ($(srcroot)/,$(dir $(CURDIR)))
|
||||
# Building in a subdirectory of the source.
|
||||
srcroot := ..
|
||||
endif
|
||||
|
||||
objtree := .
|
||||
export srctree := $(if $(KBUILD_EXTMOD),$(abs_srctree),$(srcroot))
|
||||
|
||||
VPATH :=
|
||||
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
ifdef building_out_of_srctree
|
||||
VPATH := $(srctree)
|
||||
export VPATH := $(srcroot)
|
||||
else
|
||||
VPATH :=
|
||||
endif
|
||||
endif
|
||||
|
||||
export building_out_of_srctree srctree objtree VPATH
|
||||
|
||||
# To make sure we do not include .config for any of the *config targets
|
||||
# catch them early, and hand them over to scripts/kconfig/Makefile
|
||||
@ -276,7 +301,7 @@ no-dot-config-targets := $(clean-targets) \
|
||||
outputmakefile rustavailable rustfmt rustfmtcheck
|
||||
no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
|
||||
image_name
|
||||
single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.symtypes %/
|
||||
single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %/
|
||||
|
||||
config-build :=
|
||||
mixed-build :=
|
||||
@ -354,7 +379,7 @@ else # !mixed-build
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
|
||||
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
|
||||
KERNELRELEASE = $(call read-file, include/config/kernel.release)
|
||||
KERNELRELEASE = $(call read-file, $(objtree)/include/config/kernel.release)
|
||||
KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
|
||||
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
|
||||
|
||||
@ -513,7 +538,7 @@ KGZIP = gzip
|
||||
KBZIP2 = bzip2
|
||||
KLZOP = lzop
|
||||
LZMA = lzma
|
||||
LZ4 = lz4c
|
||||
LZ4 = lz4
|
||||
XZ = xz
|
||||
ZSTD = zstd
|
||||
|
||||
@ -543,7 +568,7 @@ USERINCLUDE := \
|
||||
LINUXINCLUDE := \
|
||||
-I$(srctree)/arch/$(SRCARCH)/include \
|
||||
-I$(objtree)/arch/$(SRCARCH)/include/generated \
|
||||
$(if $(building_out_of_srctree),-I$(srctree)/include) \
|
||||
-I$(srctree)/include \
|
||||
-I$(objtree)/include \
|
||||
$(USERINCLUDE)
|
||||
|
||||
@ -629,13 +654,25 @@ ifdef building_out_of_srctree
|
||||
# At the same time when output Makefile generated, generate .gitignore to
|
||||
# ignore whole output directory
|
||||
|
||||
ifdef KBUILD_EXTMOD
|
||||
print_env_for_makefile = \
|
||||
echo "export KBUILD_OUTPUT = $(objtree)"; \
|
||||
echo "export KBUILD_EXTMOD = $(realpath $(srcroot))" ; \
|
||||
echo "export KBUILD_EXTMOD_OUTPUT = $(CURDIR)"
|
||||
else
|
||||
print_env_for_makefile = \
|
||||
echo "export KBUILD_OUTPUT = $(CURDIR)"
|
||||
endif
|
||||
|
||||
quiet_cmd_makefile = GEN Makefile
|
||||
cmd_makefile = { \
|
||||
echo "\# Automatically generated by $(srctree)/Makefile: don't edit"; \
|
||||
echo "include $(srctree)/Makefile"; \
|
||||
echo "\# Automatically generated by $(abs_srctree)/Makefile: don't edit"; \
|
||||
$(print_env_for_makefile); \
|
||||
echo "include $(abs_srctree)/Makefile"; \
|
||||
} > Makefile
|
||||
|
||||
outputmakefile:
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
@if [ -f $(srctree)/.config -o \
|
||||
-d $(srctree)/include/config -o \
|
||||
-d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \
|
||||
@ -645,7 +682,16 @@ outputmakefile:
|
||||
echo >&2 "***"; \
|
||||
false; \
|
||||
fi
|
||||
$(Q)ln -fsn $(srctree) source
|
||||
else
|
||||
@if [ -f $(srcroot)/modules.order ]; then \
|
||||
echo >&2 "***"; \
|
||||
echo >&2 "*** The external module source tree is not clean."; \
|
||||
echo >&2 "*** Please run 'make -C $(abs_srctree) M=$(realpath $(srcroot)) clean'"; \
|
||||
echo >&2 "***"; \
|
||||
false; \
|
||||
fi
|
||||
endif
|
||||
$(Q)ln -fsn $(srcroot) source
|
||||
$(call cmd,makefile)
|
||||
$(Q)test -e .gitignore || \
|
||||
{ echo "# this is build directory, ignore it"; echo "*"; } > .gitignore
|
||||
@ -717,7 +763,7 @@ endif
|
||||
# in addition to whatever we do anyway.
|
||||
# Just "make" or "make all" shall build modules as well
|
||||
|
||||
ifneq ($(filter all modules nsdeps %compile_commands.json clang-%,$(MAKECMDGOALS)),)
|
||||
ifneq ($(filter all modules nsdeps compile_commands.json clang-%,$(MAKECMDGOALS)),)
|
||||
KBUILD_MODULES := 1
|
||||
endif
|
||||
|
||||
@ -728,7 +774,7 @@ endif
|
||||
export KBUILD_MODULES KBUILD_BUILTIN
|
||||
|
||||
ifdef need-config
|
||||
include include/config/auto.conf
|
||||
include $(objtree)/include/config/auto.conf
|
||||
endif
|
||||
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
@ -789,17 +835,22 @@ $(KCONFIG_CONFIG):
|
||||
else # !may-sync-config
|
||||
# External modules and some install targets need include/generated/autoconf.h
|
||||
# and include/config/auto.conf but do not care if they are up-to-date.
|
||||
# Use auto.conf to trigger the test
|
||||
PHONY += include/config/auto.conf
|
||||
# Use auto.conf to show the error message
|
||||
|
||||
include/config/auto.conf:
|
||||
@test -e include/generated/autoconf.h -a -e $@ || ( \
|
||||
echo >&2; \
|
||||
echo >&2 " ERROR: Kernel configuration is invalid."; \
|
||||
echo >&2 " include/generated/autoconf.h or $@ are missing.";\
|
||||
echo >&2 " Run 'make oldconfig && make prepare' on kernel src to fix it."; \
|
||||
echo >&2 ; \
|
||||
/bin/false)
|
||||
checked-configs := $(addprefix $(objtree)/, include/generated/autoconf.h include/generated/rustc_cfg include/config/auto.conf)
|
||||
missing-configs := $(filter-out $(wildcard $(checked-configs)), $(checked-configs))
|
||||
|
||||
ifdef missing-configs
|
||||
PHONY += $(objtree)/include/config/auto.conf
|
||||
|
||||
$(objtree)/include/config/auto.conf:
|
||||
@echo >&2 '***'
|
||||
@echo >&2 '*** ERROR: Kernel configuration is invalid. The following files are missing:'
|
||||
@printf >&2 '*** - %s\n' $(missing-configs)
|
||||
@echo >&2 '*** Run "make oldconfig && make prepare" on kernel source to fix it.'
|
||||
@echo >&2 '***'
|
||||
@/bin/false
|
||||
endif
|
||||
|
||||
endif # may-sync-config
|
||||
endif # need-config
|
||||
@ -1013,8 +1064,10 @@ ifdef CONFIG_CC_IS_GCC
|
||||
KBUILD_CFLAGS += -fconserve-stack
|
||||
endif
|
||||
|
||||
# change __FILE__ to the relative path from the srctree
|
||||
KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
|
||||
# change __FILE__ to the relative path to the source directory
|
||||
ifdef building_out_of_srctree
|
||||
KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srcroot)/=)
|
||||
endif
|
||||
|
||||
# include additional Makefiles when needed
|
||||
include-y := scripts/Makefile.extrawarn
|
||||
@ -1026,6 +1079,8 @@ include-$(CONFIG_KMSAN) += scripts/Makefile.kmsan
|
||||
include-$(CONFIG_UBSAN) += scripts/Makefile.ubsan
|
||||
include-$(CONFIG_KCOV) += scripts/Makefile.kcov
|
||||
include-$(CONFIG_RANDSTRUCT) += scripts/Makefile.randstruct
|
||||
include-$(CONFIG_AUTOFDO_CLANG) += scripts/Makefile.autofdo
|
||||
include-$(CONFIG_PROPELLER_CLANG) += scripts/Makefile.propeller
|
||||
include-$(CONFIG_GCC_PLUGINS) += scripts/Makefile.gcc-plugins
|
||||
|
||||
include $(addprefix $(srctree)/, $(include-y))
|
||||
@ -1106,10 +1161,6 @@ export MODLIB
|
||||
|
||||
PHONY += prepare0
|
||||
|
||||
export extmod_prefix = $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/)
|
||||
export MODORDER := $(extmod_prefix)modules.order
|
||||
export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps
|
||||
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
|
||||
build-dir := .
|
||||
@ -1204,7 +1255,8 @@ PHONY += prepare archprepare
|
||||
|
||||
archprepare: outputmakefile archheaders archscripts scripts include/config/kernel.release \
|
||||
asm-generic $(version_h) include/generated/utsrelease.h \
|
||||
include/generated/compile.h include/generated/autoconf.h remove-stale-files
|
||||
include/generated/compile.h include/generated/autoconf.h \
|
||||
include/generated/rustc_cfg remove-stale-files
|
||||
|
||||
prepare0: archprepare
|
||||
$(Q)$(MAKE) $(build)=scripts/mod
|
||||
@ -1435,6 +1487,10 @@ ifdef CONFIG_OF_EARLY_FLATTREE
|
||||
all: dtbs
|
||||
endif
|
||||
|
||||
ifdef CONFIG_GENERIC_BUILTIN_DTB
|
||||
vmlinux: dtbs
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
PHONY += scripts_dtc
|
||||
@ -1502,7 +1558,8 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \
|
||||
modules.builtin modules.builtin.modinfo modules.nsdeps \
|
||||
modules.builtin.ranges vmlinux.o.map \
|
||||
compile_commands.json rust/test \
|
||||
rust-project.json .vmlinux.objs .vmlinux.export.c
|
||||
rust-project.json .vmlinux.objs .vmlinux.export.c \
|
||||
.builtin-dtbs-list .builtin-dtb.S
|
||||
|
||||
# Directories & files removed with 'make mrproper'
|
||||
MRPROPER_FILES += include/config include/generated \
|
||||
@ -1750,18 +1807,9 @@ rusttest: prepare
|
||||
# Formatting targets
|
||||
PHONY += rustfmt rustfmtcheck
|
||||
|
||||
# We skip `rust/alloc` since we want to minimize the diff w.r.t. upstream.
|
||||
#
|
||||
# We match using absolute paths since `find` does not resolve them
|
||||
# when matching, which is a problem when e.g. `srctree` is `..`.
|
||||
# We `grep` afterwards in order to remove the directory entry itself.
|
||||
rustfmt:
|
||||
$(Q)find $(abs_srctree) -type f -name '*.rs' \
|
||||
-o -path $(abs_srctree)/rust/alloc -prune \
|
||||
-o -path $(abs_objtree)/rust/test -prune \
|
||||
| grep -Fv $(abs_srctree)/rust/alloc \
|
||||
| grep -Fv $(abs_objtree)/rust/test \
|
||||
| grep -Fv generated \
|
||||
$(Q)find $(srctree) $(RCS_FIND_IGNORE) \
|
||||
-type f -a -name '*.rs' -a ! -name '*generated*' -print \
|
||||
| xargs $(RUSTFMT) $(rustfmt_flags)
|
||||
|
||||
rustfmtcheck: rustfmt_flags = --check
|
||||
@ -1800,14 +1848,10 @@ filechk_kernel.release = echo $(KERNELRELEASE)
|
||||
KBUILD_BUILTIN :=
|
||||
KBUILD_MODULES := 1
|
||||
|
||||
build-dir := $(KBUILD_EXTMOD)
|
||||
build-dir := .
|
||||
|
||||
compile_commands.json: $(extmod_prefix)compile_commands.json
|
||||
PHONY += compile_commands.json
|
||||
|
||||
clean-dirs := $(KBUILD_EXTMOD)
|
||||
clean: private rm-files := $(KBUILD_EXTMOD)/Module.symvers $(KBUILD_EXTMOD)/modules.nsdeps \
|
||||
$(KBUILD_EXTMOD)/compile_commands.json
|
||||
clean-dirs := .
|
||||
clean: private rm-files := Module.symvers modules.nsdeps compile_commands.json
|
||||
|
||||
PHONY += prepare
|
||||
# now expand this into a simple variable to reduce the cost of shell evaluations
|
||||
@ -1866,7 +1910,7 @@ endif
|
||||
|
||||
ifdef CONFIG_MODULES
|
||||
|
||||
$(MODORDER): $(build-dir)
|
||||
modules.order: $(build-dir)
|
||||
@:
|
||||
|
||||
# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
|
||||
@ -1877,7 +1921,7 @@ ifneq ($(KBUILD_MODPOST_NOFINAL),1)
|
||||
endif
|
||||
|
||||
PHONY += modules_check
|
||||
modules_check: $(MODORDER)
|
||||
modules_check: modules.order
|
||||
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/modules-check.sh $<
|
||||
|
||||
else # CONFIG_MODULES
|
||||
@ -1918,15 +1962,15 @@ $(single-ko): single_modules
|
||||
$(single-no-ko): $(build-dir)
|
||||
@:
|
||||
|
||||
# Remove MODORDER when done because it is not the real one.
|
||||
# Remove modules.order when done because it is not the real one.
|
||||
PHONY += single_modules
|
||||
single_modules: $(single-no-ko) modules_prepare
|
||||
$(Q){ $(foreach m, $(single-ko), echo $(extmod_prefix)$(m:%.ko=%.o);) } > $(MODORDER)
|
||||
$(Q){ $(foreach m, $(single-ko), echo $(m:%.ko=%.o);) } > modules.order
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
|
||||
ifneq ($(KBUILD_MODPOST_NOFINAL),1)
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal
|
||||
endif
|
||||
$(Q)rm -f $(MODORDER)
|
||||
$(Q)rm -f modules.order
|
||||
|
||||
single-goals := $(addprefix $(build-dir)/, $(single-no-ko))
|
||||
|
||||
@ -1934,6 +1978,8 @@ KBUILD_MODULES := 1
|
||||
|
||||
endif
|
||||
|
||||
prepare: outputmakefile
|
||||
|
||||
# Preset locale variables to speed up the build process. Limit locale
|
||||
# tweaks to this spot to avoid wrong language settings when running
|
||||
# make menuconfig etc.
|
||||
@ -1949,7 +1995,7 @@ $(clean-dirs):
|
||||
|
||||
clean: $(clean-dirs)
|
||||
$(call cmd,rmfiles)
|
||||
@find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
|
||||
@find . $(RCS_FIND_IGNORE) \
|
||||
\( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
|
||||
-o -name '*.ko.*' \
|
||||
-o -name '*.dtb' -o -name '*.dtbo' \
|
||||
@ -1982,7 +2028,12 @@ tags TAGS cscope gtags: FORCE
|
||||
PHONY += rust-analyzer
|
||||
rust-analyzer:
|
||||
+$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh
|
||||
ifdef KBUILD_EXTMOD
|
||||
# FIXME: external modules must not descend into a sub-directory of the kernel
|
||||
$(Q)$(MAKE) $(build)=$(objtree)/rust src=$(srctree)/rust $@
|
||||
else
|
||||
$(Q)$(MAKE) $(build)=rust $@
|
||||
endif
|
||||
|
||||
# Script to generate missing namespace dependencies
|
||||
# ---------------------------------------------------------------------------
|
||||
@ -1998,12 +2049,12 @@ nsdeps: modules
|
||||
quiet_cmd_gen_compile_commands = GEN $@
|
||||
cmd_gen_compile_commands = $(PYTHON3) $< -a $(AR) -o $@ $(filter-out $<, $(real-prereqs))
|
||||
|
||||
$(extmod_prefix)compile_commands.json: $(srctree)/scripts/clang-tools/gen_compile_commands.py \
|
||||
compile_commands.json: $(srctree)/scripts/clang-tools/gen_compile_commands.py \
|
||||
$(if $(KBUILD_EXTMOD),, vmlinux.a $(KBUILD_VMLINUX_LIBS)) \
|
||||
$(if $(CONFIG_MODULES), $(MODORDER)) FORCE
|
||||
$(if $(CONFIG_MODULES), modules.order) FORCE
|
||||
$(call if_changed,gen_compile_commands)
|
||||
|
||||
targets += $(extmod_prefix)compile_commands.json
|
||||
targets += compile_commands.json
|
||||
|
||||
PHONY += clang-tidy clang-analyzer
|
||||
|
||||
@ -2011,7 +2062,7 @@ ifdef CONFIG_CC_IS_CLANG
|
||||
quiet_cmd_clang_tools = CHECK $<
|
||||
cmd_clang_tools = $(PYTHON3) $(srctree)/scripts/clang-tools/run-clang-tools.py $@ $<
|
||||
|
||||
clang-tidy clang-analyzer: $(extmod_prefix)compile_commands.json
|
||||
clang-tidy clang-analyzer: compile_commands.json
|
||||
$(call cmd,clang_tools)
|
||||
else
|
||||
clang-tidy clang-analyzer:
|
||||
|
39
arch/Kconfig
39
arch/Kconfig
@ -812,6 +812,45 @@ config LTO_CLANG_THIN
|
||||
If unsure, say Y.
|
||||
endchoice
|
||||
|
||||
config ARCH_SUPPORTS_AUTOFDO_CLANG
|
||||
bool
|
||||
|
||||
config AUTOFDO_CLANG
|
||||
bool "Enable Clang's AutoFDO build (EXPERIMENTAL)"
|
||||
depends on ARCH_SUPPORTS_AUTOFDO_CLANG
|
||||
depends on CC_IS_CLANG && CLANG_VERSION >= 170000
|
||||
help
|
||||
This option enables Clang’s AutoFDO build. When
|
||||
an AutoFDO profile is specified in variable
|
||||
CLANG_AUTOFDO_PROFILE during the build process,
|
||||
Clang uses the profile to optimize the kernel.
|
||||
|
||||
If no profile is specified, AutoFDO options are
|
||||
still passed to Clang to facilitate the collection
|
||||
of perf data for creating an AutoFDO profile in
|
||||
subsequent builds.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config ARCH_SUPPORTS_PROPELLER_CLANG
|
||||
bool
|
||||
|
||||
config PROPELLER_CLANG
|
||||
bool "Enable Clang's Propeller build"
|
||||
depends on ARCH_SUPPORTS_PROPELLER_CLANG
|
||||
depends on CC_IS_CLANG && CLANG_VERSION >= 190000
|
||||
help
|
||||
This option enables Clang’s Propeller build. When the Propeller
|
||||
profiles is specified in variable CLANG_PROPELLER_PROFILE_PREFIX
|
||||
during the build process, Clang uses the profiles to optimize
|
||||
the kernel.
|
||||
|
||||
If no profile is specified, Propeller options are still passed
|
||||
to Clang to facilitate the collection of perf data for creating
|
||||
the Propeller profiles in subsequent builds.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config ARCH_SUPPORTS_CFI_CLANG
|
||||
bool
|
||||
help
|
||||
|
@ -264,13 +264,13 @@ stack_protector_prepare: prepare0
|
||||
-mstack-protector-guard=tls \
|
||||
-mstack-protector-guard-offset=$(shell \
|
||||
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'\
|
||||
include/generated/asm-offsets.h))
|
||||
$(objtree)/include/generated/asm-offsets.h))
|
||||
else
|
||||
stack_protector_prepare: prepare0
|
||||
$(eval SSP_PLUGIN_CFLAGS := \
|
||||
-fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell \
|
||||
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'\
|
||||
include/generated/asm-offsets.h))
|
||||
$(objtree)/include/generated/asm-offsets.h))
|
||||
$(eval KBUILD_CFLAGS += $(SSP_PLUGIN_CFLAGS))
|
||||
$(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
|
||||
endif
|
||||
|
@ -71,7 +71,7 @@ stack_protector_prepare: prepare0
|
||||
-mstack-protector-guard-reg=sp_el0 \
|
||||
-mstack-protector-guard-offset=$(shell \
|
||||
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \
|
||||
include/generated/asm-offsets.h))
|
||||
$(objtree)/include/generated/asm-offsets.h))
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARM64_BTI_KERNEL),y)
|
||||
|
@ -59,6 +59,7 @@
|
||||
#endif
|
||||
.endm
|
||||
|
||||
__HEAD
|
||||
#ifndef CONFIG_NO_EXCEPT_FILL
|
||||
/*
|
||||
* Reserved space for exception handlers.
|
||||
|
@ -61,6 +61,7 @@ SECTIONS
|
||||
/* read-only */
|
||||
_text = .; /* Text and read-only data */
|
||||
.text : {
|
||||
HEAD_TEXT
|
||||
TEXT_TEXT
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
|
@ -403,10 +403,12 @@ PHONY += stack_protector_prepare
|
||||
stack_protector_prepare: prepare0
|
||||
ifdef CONFIG_PPC64
|
||||
$(eval KBUILD_CFLAGS += -mstack-protector-guard=tls -mstack-protector-guard-reg=r13 \
|
||||
-mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' include/generated/asm-offsets.h))
|
||||
-mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' \
|
||||
$(objtree)/include/generated/asm-offsets.h))
|
||||
else
|
||||
$(eval KBUILD_CFLAGS += -mstack-protector-guard=tls -mstack-protector-guard-reg=r2 \
|
||||
-mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' include/generated/asm-offsets.h))
|
||||
-mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' \
|
||||
$(objtree)/include/generated/asm-offsets.h))
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -135,7 +135,7 @@ stack_protector_prepare: prepare0
|
||||
-mstack-protector-guard-reg=tp \
|
||||
-mstack-protector-guard-offset=$(shell \
|
||||
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \
|
||||
include/generated/asm-offsets.h))
|
||||
$(objtree)/include/generated/asm-offsets.h))
|
||||
endif
|
||||
|
||||
# arch specific predefines for sparse
|
||||
|
@ -48,6 +48,11 @@ SECTIONS
|
||||
{
|
||||
_text = .;
|
||||
HEAD_TEXT
|
||||
ALIGN_FUNCTION();
|
||||
#ifdef CONFIG_SPARC64
|
||||
/* Match text section symbols in head_64.S first */
|
||||
*head_64.o(.text)
|
||||
#endif
|
||||
TEXT_TEXT
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
|
@ -128,6 +128,8 @@ config X86
|
||||
select ARCH_SUPPORTS_LTO_CLANG
|
||||
select ARCH_SUPPORTS_LTO_CLANG_THIN
|
||||
select ARCH_SUPPORTS_RT
|
||||
select ARCH_SUPPORTS_AUTOFDO_CLANG
|
||||
select ARCH_SUPPORTS_PROPELLER_CLANG if X86_64
|
||||
select ARCH_USE_BUILTIN_BSWAP
|
||||
select ARCH_USE_CMPXCHG_LOCKREF if X86_CMPXCHG64
|
||||
select ARCH_USE_MEMTEST
|
||||
|
@ -420,6 +420,10 @@ SECTIONS
|
||||
|
||||
STABS_DEBUG
|
||||
DWARF_DEBUG
|
||||
#ifdef CONFIG_PROPELLER_CLANG
|
||||
.llvm_bb_addr_map : { *(.llvm_bb_addr_map) }
|
||||
#endif
|
||||
|
||||
ELF_DETAILS
|
||||
|
||||
DISCARDS
|
||||
|
@ -40,9 +40,7 @@ hostprogs += makemapdata
|
||||
makemapdata-objs := makemapdata.o
|
||||
|
||||
quiet_cmd_mkmap = MKMAP $@
|
||||
cmd_mkmap = TOPDIR=$(srctree) \
|
||||
SPKDIR=$(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD),$(srctree)/drivers/accessibility/speakup) \
|
||||
$(obj)/makemapdata > $@
|
||||
cmd_mkmap = TOPDIR=$(srctree) SPKDIR=$(src) $(obj)/makemapdata > $@
|
||||
|
||||
$(obj)/mapdata.h: $(obj)/makemapdata
|
||||
$(call cmd,mkmap)
|
||||
|
@ -2,6 +2,12 @@
|
||||
config DTC
|
||||
bool
|
||||
|
||||
config GENERIC_BUILTIN_DTB
|
||||
bool
|
||||
|
||||
config BUILTIN_DTB_ALL
|
||||
bool
|
||||
|
||||
menuconfig OF
|
||||
bool "Device Tree and Open Firmware support"
|
||||
help
|
||||
|
@ -21,7 +21,7 @@ config USB_DWC2
|
||||
if USB_DWC2
|
||||
|
||||
choice
|
||||
bool "DWC2 Mode Selection"
|
||||
prompt "DWC2 Mode Selection"
|
||||
default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET)
|
||||
default USB_DWC2_HOST if (USB && !USB_GADGET)
|
||||
default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET)
|
||||
|
@ -23,7 +23,7 @@ config USB_DWC3_ULPI
|
||||
controller.
|
||||
|
||||
choice
|
||||
bool "DWC3 Mode Selection"
|
||||
prompt "DWC3 Mode Selection"
|
||||
default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
|
||||
default USB_DWC3_HOST if (USB && !USB_GADGET)
|
||||
default USB_DWC3_GADGET if (!USB && USB_GADGET)
|
||||
|
@ -26,7 +26,7 @@ config USB_ISP1761_UDC
|
||||
if USB_ISP1760
|
||||
|
||||
choice
|
||||
bool "ISP1760 Mode Selection"
|
||||
prompt "ISP1760 Mode Selection"
|
||||
default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET)
|
||||
default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET)
|
||||
default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET)
|
||||
|
@ -21,7 +21,7 @@ config USB_MTU3
|
||||
|
||||
if USB_MTU3
|
||||
choice
|
||||
bool "MTU3 Mode Selection"
|
||||
prompt "MTU3 Mode Selection"
|
||||
default USB_MTU3_DUAL_ROLE if (USB && USB_GADGET)
|
||||
default USB_MTU3_HOST if (USB && !USB_GADGET)
|
||||
default USB_MTU3_GADGET if (!USB && USB_GADGET)
|
||||
|
@ -29,7 +29,7 @@ config USB_MUSB_HDRC
|
||||
if USB_MUSB_HDRC
|
||||
|
||||
choice
|
||||
bool "MUSB Mode Selection"
|
||||
prompt "MUSB Mode Selection"
|
||||
default USB_MUSB_DUAL_ROLE if (USB && USB_GADGET)
|
||||
default USB_MUSB_HOST if (USB && !USB_GADGET)
|
||||
default USB_MUSB_GADGET if (!USB && USB_GADGET)
|
||||
|
@ -95,18 +95,25 @@
|
||||
* With LTO_CLANG, the linker also splits sections by default, so we need
|
||||
* these macros to combine the sections during the final link.
|
||||
*
|
||||
* With AUTOFDO_CLANG and PROPELLER_CLANG, by default, the linker splits
|
||||
* text sections and regroups functions into subsections.
|
||||
*
|
||||
* RODATA_MAIN is not used because existing code already defines .rodata.x
|
||||
* sections to be brought in with rodata.
|
||||
*/
|
||||
#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG)
|
||||
#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG) || \
|
||||
defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
|
||||
#define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
|
||||
#else
|
||||
#define TEXT_MAIN .text
|
||||
#endif
|
||||
#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG)
|
||||
#define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data..L* .data..compoundliteral* .data.$__unnamed_* .data.$L*
|
||||
#define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]*
|
||||
#define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L*
|
||||
#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..L* .bss..compoundliteral*
|
||||
#define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]*
|
||||
#else
|
||||
#define TEXT_MAIN .text
|
||||
#define DATA_MAIN .data
|
||||
#define SDATA_MAIN .sdata
|
||||
#define RODATA_MAIN .rodata
|
||||
@ -350,9 +357,9 @@
|
||||
*(.data..decrypted) \
|
||||
*(.ref.data) \
|
||||
*(.data..shared_aligned) /* percpu related */ \
|
||||
*(.data.unlikely) \
|
||||
*(.data..unlikely) \
|
||||
__start_once = .; \
|
||||
*(.data.once) \
|
||||
*(.data..once) \
|
||||
__end_once = .; \
|
||||
STRUCT_ALIGN(); \
|
||||
*(__tracepoints) \
|
||||
@ -549,24 +556,44 @@
|
||||
__cpuidle_text_end = .; \
|
||||
__noinstr_text_end = .;
|
||||
|
||||
#define TEXT_SPLIT \
|
||||
__split_text_start = .; \
|
||||
*(.text.split .text.split.[0-9a-zA-Z_]*) \
|
||||
__split_text_end = .;
|
||||
|
||||
#define TEXT_UNLIKELY \
|
||||
__unlikely_text_start = .; \
|
||||
*(.text.unlikely .text.unlikely.*) \
|
||||
__unlikely_text_end = .;
|
||||
|
||||
#define TEXT_HOT \
|
||||
__hot_text_start = .; \
|
||||
*(.text.hot .text.hot.*) \
|
||||
__hot_text_end = .;
|
||||
|
||||
/*
|
||||
* .text section. Map to function alignment to avoid address changes
|
||||
* during second ld run in second ld pass when generating System.map
|
||||
*
|
||||
* TEXT_MAIN here will match .text.fixup and .text.unlikely if dead
|
||||
* code elimination is enabled, so these sections should be converted
|
||||
* to use ".." first.
|
||||
* TEXT_MAIN here will match symbols with a fixed pattern (for example,
|
||||
* .text.hot or .text.unlikely) if dead code elimination or
|
||||
* function-section is enabled. Match these symbols first before
|
||||
* TEXT_MAIN to ensure they are grouped together.
|
||||
*
|
||||
* Also placing .text.hot section at the beginning of a page, this
|
||||
* would help the TLB performance.
|
||||
*/
|
||||
#define TEXT_TEXT \
|
||||
ALIGN_FUNCTION(); \
|
||||
*(.text.hot .text.hot.*) \
|
||||
*(TEXT_MAIN .text.fixup) \
|
||||
*(.text.unlikely .text.unlikely.*) \
|
||||
*(.text.asan.* .text.tsan.*) \
|
||||
*(.text.unknown .text.unknown.*) \
|
||||
TEXT_SPLIT \
|
||||
TEXT_UNLIKELY \
|
||||
. = ALIGN(PAGE_SIZE); \
|
||||
TEXT_HOT \
|
||||
*(TEXT_MAIN .text.fixup) \
|
||||
NOINSTR_TEXT \
|
||||
*(.ref.text) \
|
||||
*(.text.asan.* .text.tsan.*)
|
||||
|
||||
*(.ref.text)
|
||||
|
||||
/* sched.text is aling to function alignment to secure we have same
|
||||
* address even at second ld pass when generating System.map */
|
||||
|
@ -46,7 +46,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
|
||||
} \
|
||||
} while (0)
|
||||
#define VM_WARN_ON_ONCE_PAGE(cond, page) ({ \
|
||||
static bool __section(".data.once") __warned; \
|
||||
static bool __section(".data..once") __warned; \
|
||||
int __ret_warn_once = !!(cond); \
|
||||
\
|
||||
if (unlikely(__ret_warn_once && !__warned)) { \
|
||||
@ -66,7 +66,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
|
||||
unlikely(__ret_warn); \
|
||||
})
|
||||
#define VM_WARN_ON_ONCE_FOLIO(cond, folio) ({ \
|
||||
static bool __section(".data.once") __warned; \
|
||||
static bool __section(".data..once") __warned; \
|
||||
int __ret_warn_once = !!(cond); \
|
||||
\
|
||||
if (unlikely(__ret_warn_once && !__warned)) { \
|
||||
@ -77,7 +77,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
|
||||
unlikely(__ret_warn_once); \
|
||||
})
|
||||
#define VM_WARN_ON_ONCE_MM(cond, mm) ({ \
|
||||
static bool __section(".data.once") __warned; \
|
||||
static bool __section(".data..once") __warned; \
|
||||
int __ret_warn_once = !!(cond); \
|
||||
\
|
||||
if (unlikely(__ret_warn_once && !__warned)) { \
|
||||
|
@ -247,7 +247,7 @@ extern void cleanup_module(void);
|
||||
#ifdef MODULE
|
||||
/* Creates an alias so file2alias.c can find device table. */
|
||||
#define MODULE_DEVICE_TABLE(type, name) \
|
||||
extern typeof(name) __mod_##type##__##name##_device_table \
|
||||
extern typeof(name) __mod_device_table__##type##__##name \
|
||||
__attribute__ ((unused, alias(__stringify(name))))
|
||||
#else /* !MODULE */
|
||||
#define MODULE_DEVICE_TABLE(type, name)
|
||||
|
@ -46,7 +46,7 @@ void __do_once_sleepable_done(bool *done, struct static_key_true *once_key,
|
||||
#define DO_ONCE(func, ...) \
|
||||
({ \
|
||||
bool ___ret = false; \
|
||||
static bool __section(".data.once") ___done = false; \
|
||||
static bool __section(".data..once") ___done = false; \
|
||||
static DEFINE_STATIC_KEY_TRUE(___once_key); \
|
||||
if (static_branch_unlikely(&___once_key)) { \
|
||||
unsigned long ___flags; \
|
||||
@ -64,7 +64,7 @@ void __do_once_sleepable_done(bool *done, struct static_key_true *once_key,
|
||||
#define DO_ONCE_SLEEPABLE(func, ...) \
|
||||
({ \
|
||||
bool ___ret = false; \
|
||||
static bool __section(".data.once") ___done = false; \
|
||||
static bool __section(".data..once") ___done = false; \
|
||||
static DEFINE_STATIC_KEY_TRUE(___once_key); \
|
||||
if (static_branch_unlikely(&___once_key)) { \
|
||||
___ret = __do_once_sleepable_start(&___done); \
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#define __ONCE_LITE_IF(condition) \
|
||||
({ \
|
||||
static bool __section(".data.once") __already_done; \
|
||||
static bool __section(".data..once") __already_done; \
|
||||
bool __ret_cond = !!(condition); \
|
||||
bool __ret_once = false; \
|
||||
\
|
||||
|
@ -401,7 +401,7 @@ static inline int debug_lockdep_rcu_enabled(void)
|
||||
*/
|
||||
#define RCU_LOCKDEP_WARN(c, s) \
|
||||
do { \
|
||||
static bool __section(".data.unlikely") __warned; \
|
||||
static bool __section(".data..unlikely") __warned; \
|
||||
if (debug_lockdep_rcu_enabled() && (c) && \
|
||||
debug_lockdep_rcu_enabled() && !__warned) { \
|
||||
__warned = true; \
|
||||
|
@ -27,7 +27,7 @@ void netdev_info(const struct net_device *dev, const char *format, ...);
|
||||
|
||||
#define netdev_level_once(level, dev, fmt, ...) \
|
||||
do { \
|
||||
static bool __section(".data.once") __print_once; \
|
||||
static bool __section(".data..once") __print_once; \
|
||||
\
|
||||
if (!__print_once) { \
|
||||
__print_once = true; \
|
||||
|
@ -49,7 +49,7 @@ struct folio_batch;
|
||||
* when we specify __GFP_NOWARN.
|
||||
*/
|
||||
#define WARN_ON_ONCE_GFP(cond, gfp) ({ \
|
||||
static bool __section(".data.once") __warned; \
|
||||
static bool __section(".data..once") __warned; \
|
||||
int __ret_warn_once = !!(cond); \
|
||||
\
|
||||
if (unlikely(!(gfp & __GFP_NOWARN) && __ret_warn_once && !__warned)) { \
|
||||
|
@ -372,8 +372,8 @@ rust-analyzer:
|
||||
$(Q)$(srctree)/scripts/generate_rust_analyzer.py \
|
||||
--cfgs='core=$(core-cfgs)' \
|
||||
$(realpath $(srctree)) $(realpath $(objtree)) \
|
||||
$(rustc_sysroot) $(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \
|
||||
$(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json
|
||||
$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
|
||||
> rust-project.json
|
||||
|
||||
redirect-intrinsics = \
|
||||
__addsf3 __eqsf2 __extendsfdf2 __gesf2 __lesf2 __ltsf2 __mulsf3 __nesf2 __truncdfsf2 __unordsf2 \
|
||||
|
@ -205,7 +205,7 @@ if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:)
|
||||
|
||||
cmd_and_fixdep = \
|
||||
$(cmd); \
|
||||
scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\
|
||||
$(objtree)/scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\
|
||||
rm -f $(depfile)
|
||||
|
||||
# Usage: $(call if_changed_rule,foo)
|
||||
|
24
scripts/Makefile.autofdo
Normal file
24
scripts/Makefile.autofdo
Normal file
@ -0,0 +1,24 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Enable available and selected Clang AutoFDO features.
|
||||
|
||||
CFLAGS_AUTOFDO_CLANG := -fdebug-info-for-profiling -mllvm -enable-fs-discriminator=true -mllvm -improved-fs-discriminator=true
|
||||
|
||||
ifndef CONFIG_DEBUG_INFO
|
||||
CFLAGS_AUTOFDO_CLANG += -gmlt
|
||||
endif
|
||||
|
||||
ifdef CLANG_AUTOFDO_PROFILE
|
||||
CFLAGS_AUTOFDO_CLANG += -fprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -ffunction-sections
|
||||
CFLAGS_AUTOFDO_CLANG += -fsplit-machine-functions
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LTO_CLANG_THIN
|
||||
ifdef CLANG_AUTOFDO_PROFILE
|
||||
KBUILD_LDFLAGS += --lto-sample-profile=$(CLANG_AUTOFDO_PROFILE)
|
||||
endif
|
||||
KBUILD_LDFLAGS += --mllvm=-enable-fs-discriminator=true --mllvm=-improved-fs-discriminator=true -plugin-opt=thinlto
|
||||
KBUILD_LDFLAGS += -plugin-opt=-split-machine-functions
|
||||
endif
|
||||
|
||||
export CFLAGS_AUTOFDO_CLANG
|
@ -3,7 +3,7 @@
|
||||
# Building
|
||||
# ==========================================================================
|
||||
|
||||
src := $(if $(VPATH),$(VPATH)/)$(obj)
|
||||
src := $(srcroot)/$(obj)
|
||||
|
||||
PHONY := $(obj)/
|
||||
$(obj)/:
|
||||
@ -34,7 +34,7 @@ subdir-asflags-y :=
|
||||
subdir-ccflags-y :=
|
||||
|
||||
# Read auto.conf if it exists, otherwise ignore
|
||||
-include include/config/auto.conf
|
||||
-include $(objtree)/include/config/auto.conf
|
||||
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
include $(srctree)/scripts/Makefile.compiler
|
||||
@ -107,20 +107,14 @@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $<
|
||||
$(obj)/%.i: $(obj)/%.c FORCE
|
||||
$(call if_changed_dep,cpp_i_c)
|
||||
|
||||
genksyms = scripts/genksyms/genksyms \
|
||||
$(if $(1), -T $(2)) \
|
||||
$(if $(KBUILD_PRESERVE), -p) \
|
||||
-r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null)
|
||||
genksyms = $(objtree)/scripts/genksyms/genksyms \
|
||||
$(if $(KBUILD_SYMTYPES), -T $(@:.o=.symtypes)) \
|
||||
$(if $(KBUILD_PRESERVE), -p) \
|
||||
$(addprefix -r , $(wildcard $(@:.o=.symref)))
|
||||
|
||||
# These mirror gensymtypes_S and co below, keep them in synch.
|
||||
cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms)
|
||||
|
||||
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
|
||||
cmd_cc_symtypes_c = $(call cmd_gensymtypes_c,true,$@) >/dev/null
|
||||
|
||||
$(obj)/%.symtypes : $(obj)/%.c FORCE
|
||||
$(call cmd,cc_symtypes_c)
|
||||
|
||||
# LLVM assembly
|
||||
# Generate .ll files from .c
|
||||
quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@
|
||||
@ -135,17 +129,6 @@ $(obj)/%.ll: $(obj)/%.c FORCE
|
||||
|
||||
is-single-obj-m = $(and $(part-of-module),$(filter $@, $(obj-m)),y)
|
||||
|
||||
# When a module consists of a single object, there is no reason to keep LLVM IR.
|
||||
# Make $(LD) covert LLVM IR to ELF here.
|
||||
ifdef CONFIG_LTO_CLANG
|
||||
cmd_ld_single_m = $(if $(is-single-obj-m), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@)
|
||||
endif
|
||||
|
||||
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
|
||||
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \
|
||||
$(cmd_ld_single_m) \
|
||||
$(cmd_objtool)
|
||||
|
||||
ifdef CONFIG_MODVERSIONS
|
||||
# When module versioning is enabled the following steps are executed:
|
||||
# o compile a <file>.o from <file>.c
|
||||
@ -158,8 +141,7 @@ ifdef CONFIG_MODVERSIONS
|
||||
|
||||
gen_symversions = \
|
||||
if $(NM) $@ 2>/dev/null | grep -q ' __export_symbol_'; then \
|
||||
$(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
|
||||
>> $(dot-target).cmd; \
|
||||
$(cmd_gensymtypes_$1) >> $(dot-target).cmd; \
|
||||
fi
|
||||
|
||||
cmd_gen_symversions_c = $(call gen_symversions,c)
|
||||
@ -207,23 +189,6 @@ ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),)
|
||||
cmd_warn_shared_object = $(if $(word 2, $(modname-multi)),$(warning $(kbuild-file): $*.o is added to multiple modules: $(modname-multi)))
|
||||
endif
|
||||
|
||||
define rule_cc_o_c
|
||||
$(call cmd_and_fixdep,cc_o_c)
|
||||
$(call cmd,checksrc)
|
||||
$(call cmd,checkdoc)
|
||||
$(call cmd,gen_objtooldep)
|
||||
$(call cmd,gen_symversions_c)
|
||||
$(call cmd,record_mcount)
|
||||
$(call cmd,warn_shared_object)
|
||||
endef
|
||||
|
||||
define rule_as_o_S
|
||||
$(call cmd_and_fixdep,as_o_S)
|
||||
$(call cmd,gen_objtooldep)
|
||||
$(call cmd,gen_symversions_S)
|
||||
$(call cmd,warn_shared_object)
|
||||
endef
|
||||
|
||||
# Built-in and composite module parts
|
||||
$(obj)/%.o: $(obj)/%.c $(recordmcount_source) FORCE
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
@ -330,22 +295,12 @@ cmd_gensymtypes_S = \
|
||||
$(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/EXPORT_SYMBOL(\1);/p' ; } | \
|
||||
$(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms)
|
||||
|
||||
quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@
|
||||
cmd_cc_symtypes_S = $(call cmd_gensymtypes_S,true,$@) >/dev/null
|
||||
|
||||
$(obj)/%.symtypes : $(obj)/%.S FORCE
|
||||
$(call cmd,cc_symtypes_S)
|
||||
|
||||
|
||||
quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@
|
||||
cmd_cpp_s_S = $(CPP) $(a_flags) -o $@ $<
|
||||
|
||||
$(obj)/%.s: $(obj)/%.S FORCE
|
||||
$(call if_changed_dep,cpp_s_S)
|
||||
|
||||
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
|
||||
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool)
|
||||
|
||||
ifdef CONFIG_ASM_MODVERSIONS
|
||||
|
||||
# versioning matches the C process described above, with difference that
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Cleaning up
|
||||
# ==========================================================================
|
||||
|
||||
src := $(if $(VPATH),$(VPATH)/)$(obj)
|
||||
src := $(srcroot)/$(obj)
|
||||
|
||||
PHONY := __clean
|
||||
__clean:
|
||||
|
@ -13,7 +13,7 @@ cc-cross-prefix = $(firstword $(foreach c, $(1), \
|
||||
$(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c))))
|
||||
|
||||
# output directory for tests below
|
||||
TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$
|
||||
TMPOUT = .tmp_$$$$
|
||||
|
||||
# try-run
|
||||
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
|
||||
|
@ -96,12 +96,10 @@ hostrust_flags = --out-dir $(dir $@) --emit=dep-info=$(depfile) \
|
||||
$(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \
|
||||
$(HOSTRUSTFLAGS_$(target-stem))
|
||||
|
||||
# $(objtree)/$(obj) for including generated headers from checkin source files
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
# $(obj) for including generated headers from checkin source files
|
||||
ifdef building_out_of_srctree
|
||||
hostc_flags += -I $(objtree)/$(obj)
|
||||
hostcxx_flags += -I $(objtree)/$(obj)
|
||||
endif
|
||||
hostc_flags += -I $(obj)
|
||||
hostcxx_flags += -I $(obj)
|
||||
endif
|
||||
|
||||
#####
|
||||
|
@ -191,15 +191,33 @@ _c_flags += $(if $(patsubst n%,, \
|
||||
-D__KCSAN_INSTRUMENT_BARRIERS__)
|
||||
endif
|
||||
|
||||
#
|
||||
# Enable AutoFDO build flags except some files or directories we don't want to
|
||||
# enable (depends on variables AUTOFDO_PROFILE_obj.o and AUTOFDO_PROFILE).
|
||||
#
|
||||
ifeq ($(CONFIG_AUTOFDO_CLANG),y)
|
||||
_c_flags += $(if $(patsubst n%,, \
|
||||
$(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(is-kernel-object)), \
|
||||
$(CFLAGS_AUTOFDO_CLANG))
|
||||
endif
|
||||
|
||||
#
|
||||
# Enable Propeller build flags except some files or directories we don't want to
|
||||
# enable (depends on variables AUTOFDO_PROPELLER_obj.o and PROPELLER_PROFILE).
|
||||
#
|
||||
ifdef CONFIG_PROPELLER_CLANG
|
||||
_c_flags += $(if $(patsubst n%,, \
|
||||
$(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(PROPELLER_PROFILE))$(is-kernel-object), \
|
||||
$(CFLAGS_PROPELLER_CLANG))
|
||||
endif
|
||||
|
||||
# $(src) for including checkin headers from generated source files
|
||||
# $(obj) for including generated headers from checkin source files
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
ifdef building_out_of_srctree
|
||||
_c_flags += $(addprefix -I, $(src) $(obj))
|
||||
_a_flags += $(addprefix -I, $(src) $(obj))
|
||||
_cpp_flags += $(addprefix -I, $(src) $(obj))
|
||||
endif
|
||||
endif
|
||||
|
||||
# If $(is-kernel-object) is 'y', this object will be linked to vmlinux or modules
|
||||
is-kernel-object = $(or $(part-of-builtin),$(part-of-module))
|
||||
@ -280,6 +298,42 @@ $(foreach m, $1, \
|
||||
$(addprefix $(obj)/, $(call suffix-search, $(patsubst $(obj)/%,%,$m), $2, $3))))
|
||||
endef
|
||||
|
||||
# Build commands
|
||||
# ===========================================================================
|
||||
# These are shared by some Makefile.* files.
|
||||
|
||||
objtool-enabled := y
|
||||
|
||||
ifdef CONFIG_LTO_CLANG
|
||||
# objtool cannot process LLVM IR. Make $(LD) covert LLVM IR to ELF here.
|
||||
cmd_ld_single = $(if $(objtool-enabled), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@)
|
||||
endif
|
||||
|
||||
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
|
||||
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \
|
||||
$(cmd_ld_single) \
|
||||
$(cmd_objtool)
|
||||
|
||||
define rule_cc_o_c
|
||||
$(call cmd_and_fixdep,cc_o_c)
|
||||
$(call cmd,checksrc)
|
||||
$(call cmd,checkdoc)
|
||||
$(call cmd,gen_objtooldep)
|
||||
$(call cmd,gen_symversions_c)
|
||||
$(call cmd,record_mcount)
|
||||
$(call cmd,warn_shared_object)
|
||||
endef
|
||||
|
||||
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
|
||||
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool)
|
||||
|
||||
define rule_as_o_S
|
||||
$(call cmd_and_fixdep,as_o_S)
|
||||
$(call cmd,gen_objtooldep)
|
||||
$(call cmd,gen_symversions_S)
|
||||
$(call cmd,warn_shared_object)
|
||||
endef
|
||||
|
||||
# Copy a file
|
||||
# ===========================================================================
|
||||
# 'cp' preserves permissions. If you use it to copy a file in read-only srctree,
|
||||
@ -371,10 +425,10 @@ quiet_cmd_lzo_with_size = LZO $@
|
||||
cmd_lzo_with_size = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@
|
||||
|
||||
quiet_cmd_lz4 = LZ4 $@
|
||||
cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout > $@
|
||||
cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -9 - - > $@
|
||||
|
||||
quiet_cmd_lz4_with_size = LZ4 $@
|
||||
cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout; \
|
||||
cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -9 - -; \
|
||||
$(size_append); } > $@
|
||||
|
||||
# U-Boot mkimage
|
||||
|
@ -6,14 +6,12 @@
|
||||
PHONY := __modfinal
|
||||
__modfinal:
|
||||
|
||||
include include/config/auto.conf
|
||||
include $(objtree)/include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
|
||||
# for c_flags
|
||||
include $(srctree)/scripts/Makefile.lib
|
||||
|
||||
# find all modules listed in modules.order
|
||||
modules := $(call read-file, $(MODORDER))
|
||||
modules := $(call read-file, modules.order)
|
||||
|
||||
__modfinal: $(modules:%.o=%.ko)
|
||||
@:
|
||||
@ -22,30 +20,27 @@ __modfinal: $(modules:%.o=%.ko)
|
||||
modname = $(notdir $(@:.mod.o=))
|
||||
part-of-module = y
|
||||
GCOV_PROFILE := n
|
||||
KCSAN_SANITIZE := n
|
||||
|
||||
quiet_cmd_cc_o_c = CC [M] $@
|
||||
cmd_cc_o_c = $(CC) $(filter-out $(CC_FLAGS_CFI), $(c_flags)) -c -o $@ $<
|
||||
ccflags-remove-y := $(CC_FLAGS_CFI)
|
||||
|
||||
%.mod.o: %.mod.c FORCE
|
||||
$(call if_changed_dep,cc_o_c)
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
|
||||
$(extmod_prefix).module-common.o: $(srctree)/scripts/module-common.c FORCE
|
||||
$(call if_changed_dep,cc_o_c)
|
||||
.module-common.o: $(srctree)/scripts/module-common.c FORCE
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
|
||||
quiet_cmd_ld_ko_o = LD [M] $@
|
||||
cmd_ld_ko_o = \
|
||||
$(LD) -r $(KBUILD_LDFLAGS) \
|
||||
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
|
||||
-T scripts/module.lds -o $@ $(filter %.o, $^)
|
||||
-T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^)
|
||||
|
||||
quiet_cmd_btf_ko = BTF [M] $@
|
||||
cmd_btf_ko = \
|
||||
if [ ! -f vmlinux ]; then \
|
||||
if [ ! -f $(objtree)/vmlinux ]; then \
|
||||
printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \
|
||||
else \
|
||||
LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base vmlinux $@; \
|
||||
$(RESOLVE_BTFIDS) -b vmlinux $@; \
|
||||
LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base $(objtree)/vmlinux $@; \
|
||||
$(RESOLVE_BTFIDS) -b $(objtree)/vmlinux $@; \
|
||||
fi;
|
||||
|
||||
# Same as newer-prereqs, but allows to exclude specified extra dependencies
|
||||
@ -57,13 +52,13 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \
|
||||
printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
|
||||
|
||||
# Re-generate module BTFs if either module's .ko or vmlinux changed
|
||||
%.ko: %.o %.mod.o $(extmod_prefix).module-common.o scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),vmlinux) FORCE
|
||||
+$(call if_changed_except,ld_ko_o,vmlinux)
|
||||
%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
|
||||
+$(call if_changed_except,ld_ko_o,$(objtree)/vmlinux)
|
||||
ifdef CONFIG_DEBUG_INFO_BTF_MODULES
|
||||
+$(if $(newer-prereqs),$(call cmd,btf_ko))
|
||||
endif
|
||||
|
||||
targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) $(extmod_prefix).module-common.o
|
||||
targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) .module-common.o
|
||||
|
||||
# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
@ -6,7 +6,7 @@
|
||||
PHONY := __modinst
|
||||
__modinst:
|
||||
|
||||
include include/config/auto.conf
|
||||
include $(objtree)/include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
|
||||
install-y :=
|
||||
@ -40,7 +40,7 @@ $(addprefix $(MODLIB)/, modules.builtin modules.builtin.modinfo modules.builtin.
|
||||
|
||||
endif
|
||||
|
||||
modules := $(call read-file, $(MODORDER))
|
||||
modules := $(call read-file, modules.order)
|
||||
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
dst := $(MODLIB)/kernel
|
||||
@ -59,7 +59,7 @@ suffix-$(CONFIG_MODULE_COMPRESS_XZ) := .xz
|
||||
suffix-$(CONFIG_MODULE_COMPRESS_ZSTD) := .zst
|
||||
endif
|
||||
|
||||
modules := $(patsubst $(extmod_prefix)%.o, $(dst)/%.ko$(suffix-y), $(modules))
|
||||
modules := $(patsubst %.o, $(dst)/%.ko$(suffix-y), $(modules))
|
||||
install-$(CONFIG_MODULES) += $(modules)
|
||||
|
||||
__modinst: $(install-y)
|
||||
@ -119,7 +119,7 @@ endif
|
||||
# Create necessary directories
|
||||
$(foreach dir, $(sort $(dir $(install-y))), $(shell mkdir -p $(dir)))
|
||||
|
||||
$(dst)/%.ko: $(extmod_prefix)%.ko FORCE
|
||||
$(dst)/%.ko: %.ko FORCE
|
||||
$(call cmd,install)
|
||||
$(call cmd,strip)
|
||||
$(call cmd,sign)
|
||||
|
@ -35,10 +35,10 @@
|
||||
PHONY := __modpost
|
||||
__modpost:
|
||||
|
||||
include include/config/auto.conf
|
||||
include $(objtree)/include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
|
||||
MODPOST = scripts/mod/modpost
|
||||
MODPOST = $(objtree)/scripts/mod/modpost
|
||||
|
||||
modpost-args = \
|
||||
$(if $(CONFIG_MODULES),-M) \
|
||||
@ -46,7 +46,7 @@ modpost-args = \
|
||||
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \
|
||||
$(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \
|
||||
$(if $(KBUILD_MODPOST_WARN),-w) \
|
||||
$(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \
|
||||
$(if $(KBUILD_NSDEPS),-d modules.nsdeps) \
|
||||
$(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) \
|
||||
$(if $(findstring 1, $(KBUILD_EXTRA_WARN)),-W) \
|
||||
-o $@
|
||||
@ -61,8 +61,8 @@ endif
|
||||
# Read out modules.order to pass in modpost.
|
||||
# Otherwise, allmodconfig would fail with "Argument list too long".
|
||||
ifdef KBUILD_MODULES
|
||||
modpost-args += -T $(MODORDER)
|
||||
modpost-deps += $(MODORDER)
|
||||
modpost-args += -T modules.order
|
||||
modpost-deps += modules.order
|
||||
endif
|
||||
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
@ -111,19 +111,19 @@ endif
|
||||
else
|
||||
|
||||
# set src + obj - they may be used in the modules's Makefile
|
||||
obj := $(KBUILD_EXTMOD)
|
||||
src := $(if $(VPATH),$(VPATH)/)$(obj)
|
||||
obj := .
|
||||
src := $(srcroot)
|
||||
|
||||
# Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS
|
||||
include $(kbuild-file)
|
||||
|
||||
output-symdump := $(KBUILD_EXTMOD)/Module.symvers
|
||||
output-symdump := Module.symvers
|
||||
|
||||
ifeq ($(wildcard Module.symvers),)
|
||||
missing-input := Module.symvers
|
||||
ifeq ($(wildcard $(objtree)/Module.symvers),)
|
||||
missing-input := $(objtree)/Module.symvers
|
||||
else
|
||||
modpost-args += -i Module.symvers
|
||||
modpost-deps += Module.symvers
|
||||
modpost-args += -i $(objtree)/Module.symvers
|
||||
modpost-deps += $(objtree)/Module.symvers
|
||||
endif
|
||||
|
||||
modpost-args += -e $(addprefix -i , $(KBUILD_EXTRA_SYMBOLS))
|
||||
|
39
scripts/Makefile.propeller
Normal file
39
scripts/Makefile.propeller
Normal file
@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Enable available and selected Clang Propeller features.
|
||||
ifdef CLANG_PROPELLER_PROFILE_PREFIX
|
||||
CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=list=$(CLANG_PROPELLER_PROFILE_PREFIX)_cc_profile.txt -ffunction-sections
|
||||
KBUILD_LDFLAGS += --symbol-ordering-file=$(CLANG_PROPELLER_PROFILE_PREFIX)_ld_profile.txt --no-warn-symbol-ordering
|
||||
else
|
||||
# Starting with Clang v20, the '-fbasic-block-sections=labels' option is
|
||||
# deprecated. Use the recommended '-fbasic-block-address-map' option.
|
||||
# Link: https://github.com/llvm/llvm-project/pull/110039
|
||||
ifeq ($(call clang-min-version, 200000),y)
|
||||
CFLAGS_PROPELLER_CLANG := -fbasic-block-address-map
|
||||
else
|
||||
CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=labels
|
||||
endif
|
||||
endif
|
||||
|
||||
# Propeller requires debug information to embed module names in the profiles.
|
||||
# If CONFIG_DEBUG_INFO is not enabled, set -gmlt option. Skip this for AutoFDO,
|
||||
# as the option should already be set.
|
||||
ifndef CONFIG_DEBUG_INFO
|
||||
ifndef CONFIG_AUTOFDO_CLANG
|
||||
CFLAGS_PROPELLER_CLANG += -gmlt
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LTO_CLANG_THIN
|
||||
ifdef CLANG_PROPELLER_PROFILE_PREFIX
|
||||
KBUILD_LDFLAGS += --lto-basic-block-sections=$(CLANG_PROPELLER_PROFILE_PREFIX)_cc_profile.txt
|
||||
else
|
||||
ifeq ($(call test-ge, $(CONFIG_LLD_VERSION), 200000),y)
|
||||
KBUILD_LDFLAGS += --lto-basic-block-address-map
|
||||
else
|
||||
KBUILD_LDFLAGS += --lto-basic-block-sections=labels
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
export CFLAGS_PROPELLER_CLANG
|
@ -5,17 +5,53 @@ __default: vmlinux
|
||||
|
||||
include include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
|
||||
# for c_flags
|
||||
include $(srctree)/scripts/Makefile.lib
|
||||
|
||||
targets :=
|
||||
|
||||
quiet_cmd_cc_o_c = CC $@
|
||||
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
|
||||
|
||||
%.o: %.c FORCE
|
||||
$(call if_changed_dep,cc_o_c)
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
|
||||
%.o: %.S FORCE
|
||||
$(call if_changed_rule,as_o_S)
|
||||
|
||||
# Built-in dtb
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
quiet_cmd_wrap_dtbs = WRAP $@
|
||||
cmd_wrap_dtbs = { \
|
||||
echo '\#include <asm-generic/vmlinux.lds.h>'; \
|
||||
echo '.section .dtb.init.rodata,"a"'; \
|
||||
while read dtb; do \
|
||||
symbase=__dtb_$$(basename -s .dtb "$${dtb}" | tr - _); \
|
||||
echo '.balign STRUCT_ALIGNMENT'; \
|
||||
echo ".global $${symbase}_begin"; \
|
||||
echo "$${symbase}_begin:"; \
|
||||
echo '.incbin "'$$dtb'" '; \
|
||||
echo ".global $${symbase}_end"; \
|
||||
echo "$${symbase}_end:"; \
|
||||
done < $<; \
|
||||
} > $@
|
||||
|
||||
.builtin-dtbs.S: .builtin-dtbs-list FORCE
|
||||
$(call if_changed,wrap_dtbs)
|
||||
|
||||
quiet_cmd_gen_dtbs_list = GEN $@
|
||||
cmd_gen_dtbs_list = \
|
||||
$(if $(CONFIG_BUILTIN_DTB_NAME), echo "arch/$(SRCARCH)/boot/dts/$(CONFIG_BUILTIN_DTB_NAME).dtb",:) > $@
|
||||
|
||||
.builtin-dtbs-list: arch/$(SRCARCH)/boot/dts/dtbs-list FORCE
|
||||
$(call if_changed,$(if $(CONFIG_BUILTIN_DTB_ALL),copy,gen_dtbs_list))
|
||||
|
||||
targets += .builtin-dtbs-list
|
||||
|
||||
ifdef CONFIG_GENERIC_BUILTIN_DTB
|
||||
targets += .builtin-dtbs.S .builtin-dtbs.o
|
||||
vmlinux: .builtin-dtbs.o
|
||||
endif
|
||||
|
||||
# vmlinux
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ifdef CONFIG_MODULES
|
||||
targets += .vmlinux.export.o
|
||||
@ -39,6 +75,9 @@ cmd_link_vmlinux = \
|
||||
targets += vmlinux
|
||||
vmlinux: scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE
|
||||
+$(call if_changed_dep,link_vmlinux)
|
||||
ifdef CONFIG_DEBUG_INFO_BTF
|
||||
vmlinux: $(RESOLVE_BTFIDS)
|
||||
endif
|
||||
|
||||
# module.builtin.ranges
|
||||
# ---------------------------------------------------------------------------
|
||||
|
@ -80,11 +80,7 @@ command results in a shift count error.'
|
||||
NPROC=1
|
||||
else
|
||||
ONLINE=0
|
||||
if [ "$KBUILD_EXTMOD" = "" ] ; then
|
||||
OPTIONS="--dir $srctree $COCCIINCLUDE"
|
||||
else
|
||||
OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
|
||||
fi
|
||||
OPTIONS="--dir $srcroot $COCCIINCLUDE"
|
||||
|
||||
# Use only one thread per core by default if hyperthreading is enabled
|
||||
THREADS_PER_CORE=$(LANG=C lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]")
|
||||
|
@ -12,7 +12,7 @@ KERNELRELEASE=$1
|
||||
|
||||
: ${DEPMOD:=depmod}
|
||||
|
||||
if ! test -r System.map ; then
|
||||
if ! test -r "${objtree}/System.map" ; then
|
||||
echo "Warning: modules_install: missing 'System.map' file. Skipping depmod." >&2
|
||||
exit 0
|
||||
fi
|
||||
@ -25,7 +25,7 @@ if [ -z $(command -v $DEPMOD) ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -- -ae -F System.map
|
||||
set -- -ae -F "${objtree}/System.map"
|
||||
if test -n "$INSTALL_MOD_PATH"; then
|
||||
set -- "$@" -b "$INSTALL_MOD_PATH"
|
||||
fi
|
||||
|
@ -632,54 +632,55 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
|
||||
void export_symbol(const char *name)
|
||||
{
|
||||
struct symbol *sym;
|
||||
unsigned long crc;
|
||||
int has_changed = 0;
|
||||
|
||||
sym = find_symbol(name, SYM_NORMAL, 0);
|
||||
if (!sym)
|
||||
if (!sym) {
|
||||
error_with_pos("export undefined symbol %s", name);
|
||||
else {
|
||||
unsigned long crc;
|
||||
int has_changed = 0;
|
||||
|
||||
if (flag_dump_defs)
|
||||
fprintf(debugfile, "Export %s == <", name);
|
||||
|
||||
expansion_trail = (struct symbol *)-1L;
|
||||
|
||||
sym->expansion_trail = expansion_trail;
|
||||
expansion_trail = sym;
|
||||
crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
|
||||
|
||||
sym = expansion_trail;
|
||||
while (sym != (struct symbol *)-1L) {
|
||||
struct symbol *n = sym->expansion_trail;
|
||||
|
||||
if (sym->status != STATUS_UNCHANGED) {
|
||||
if (!has_changed) {
|
||||
print_location();
|
||||
fprintf(stderr, "%s: %s: modversion "
|
||||
"changed because of changes "
|
||||
"in ", flag_preserve ? "error" :
|
||||
"warning", name);
|
||||
} else
|
||||
fprintf(stderr, ", ");
|
||||
print_type_name(sym->type, sym->name);
|
||||
if (sym->status == STATUS_DEFINED)
|
||||
fprintf(stderr, " (became defined)");
|
||||
has_changed = 1;
|
||||
if (flag_preserve)
|
||||
errors++;
|
||||
}
|
||||
sym->expansion_trail = 0;
|
||||
sym = n;
|
||||
}
|
||||
if (has_changed)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (flag_dump_defs)
|
||||
fputs(">\n", debugfile);
|
||||
|
||||
printf("#SYMVER %s 0x%08lx\n", name, crc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag_dump_defs)
|
||||
fprintf(debugfile, "Export %s == <", name);
|
||||
|
||||
expansion_trail = (struct symbol *)-1L;
|
||||
|
||||
sym->expansion_trail = expansion_trail;
|
||||
expansion_trail = sym;
|
||||
crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
|
||||
|
||||
sym = expansion_trail;
|
||||
while (sym != (struct symbol *)-1L) {
|
||||
struct symbol *n = sym->expansion_trail;
|
||||
|
||||
if (sym->status != STATUS_UNCHANGED) {
|
||||
if (!has_changed) {
|
||||
print_location();
|
||||
fprintf(stderr,
|
||||
"%s: %s: modversion changed because of changes in ",
|
||||
flag_preserve ? "error" : "warning",
|
||||
name);
|
||||
} else {
|
||||
fprintf(stderr, ", ");
|
||||
}
|
||||
print_type_name(sym->type, sym->name);
|
||||
if (sym->status == STATUS_DEFINED)
|
||||
fprintf(stderr, " (became defined)");
|
||||
has_changed = 1;
|
||||
if (flag_preserve)
|
||||
errors++;
|
||||
}
|
||||
sym->expansion_trail = 0;
|
||||
sym = n;
|
||||
}
|
||||
if (has_changed)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (flag_dump_defs)
|
||||
fputs(">\n", debugfile);
|
||||
|
||||
printf("#SYMVER %s 0x%08lx\n", name, crc);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
@ -23,7 +23,6 @@ arch/m68k/coldfire/head.o
|
||||
arch/m68k/kernel/head.o
|
||||
arch/m68k/kernel/sun3-head.o
|
||||
arch/microblaze/kernel/head.o
|
||||
arch/mips/kernel/head.o
|
||||
arch/nios2/kernel/head.o
|
||||
arch/openrisc/kernel/head.o
|
||||
arch/parisc/kernel/head.o
|
||||
|
@ -628,7 +628,7 @@ static const struct option long_opts[] = {
|
||||
|
||||
static void conf_usage(const char *progname)
|
||||
{
|
||||
printf("Usage: %s [options] <kconfig-file>\n", progname);
|
||||
printf("Usage: %s [options] kconfig_file\n", progname);
|
||||
printf("\n");
|
||||
printf("Generic options:\n");
|
||||
printf(" -h, --help Print this message and exit.\n");
|
||||
@ -653,6 +653,9 @@ static void conf_usage(const char *progname)
|
||||
printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
|
||||
printf(" --mod2noconfig Change answers from mod to no if possible\n");
|
||||
printf(" (If none of the above is given, --oldaskconfig is the default)\n");
|
||||
printf("\n");
|
||||
printf("Arguments:\n");
|
||||
printf(" kconfig_file Top-level Kconfig file.\n");
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
|
@ -34,6 +34,7 @@ bool sym_string_valid(struct symbol *sym, const char *newval);
|
||||
bool sym_string_within_range(struct symbol *sym, const char *str);
|
||||
bool sym_set_string_value(struct symbol *sym, const char *newval);
|
||||
bool sym_is_changeable(const struct symbol *sym);
|
||||
struct menu *sym_get_prompt_menu(const struct symbol *sym);
|
||||
struct menu *sym_get_choice_menu(const struct symbol *sym);
|
||||
const char * sym_get_string_value(struct symbol *sym);
|
||||
|
||||
|
@ -467,7 +467,7 @@ static void handle_f9(int *key, struct menu *current_item)
|
||||
return;
|
||||
}
|
||||
|
||||
/* return != 0 to indicate the key was handles */
|
||||
/* return != 0 to indicate the key was handled */
|
||||
static int process_special_keys(int *key, struct menu *menu)
|
||||
{
|
||||
int i;
|
||||
|
@ -277,6 +277,15 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
|
||||
case KEY_RIGHT:
|
||||
menu_driver(menu, REQ_RIGHT_ITEM);
|
||||
break;
|
||||
case 9: /* TAB */
|
||||
if (btn_num > 1) {
|
||||
/* cycle through buttons */
|
||||
if (item_index(current_item(menu)) == btn_num - 1)
|
||||
menu_driver(menu, REQ_FIRST_ITEM);
|
||||
else
|
||||
menu_driver(menu, REQ_NEXT_ITEM);
|
||||
}
|
||||
break;
|
||||
case 10: /* ENTER */
|
||||
case 27: /* ESCAPE */
|
||||
case ' ':
|
||||
|
@ -24,7 +24,6 @@
|
||||
int cdebug = PRINTD;
|
||||
|
||||
static void yyerror(const char *err);
|
||||
static void zconfprint(const char *err, ...);
|
||||
static void zconf_error(const char *err, ...);
|
||||
static bool zconf_endtoken(const char *tokenname,
|
||||
const char *expected_tokenname);
|
||||
@ -183,7 +182,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list
|
||||
if (current_entry->prompt)
|
||||
current_entry->prompt->type = P_MENU;
|
||||
else
|
||||
zconfprint("warning: menuconfig statement without prompt");
|
||||
zconf_error("menuconfig statement without prompt");
|
||||
printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
|
||||
};
|
||||
|
||||
@ -293,12 +292,6 @@ choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
|
||||
printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
|
||||
};
|
||||
|
||||
choice_option: T_BOOL T_WORD_QUOTE if_expr T_EOL
|
||||
{
|
||||
menu_add_prompt(P_PROMPT, $2, $3);
|
||||
printd(DEBUG_PARSE, "%s:%d:bool\n", cur_filename, cur_lineno);
|
||||
};
|
||||
|
||||
choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
|
||||
{
|
||||
menu_add_symbol(P_DEFAULT, $2, $3);
|
||||
@ -408,14 +401,14 @@ help: help_start T_HELPTEXT
|
||||
{
|
||||
if (current_entry->help) {
|
||||
free(current_entry->help);
|
||||
zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used",
|
||||
current_entry->sym->name ?: "<choice>");
|
||||
zconf_error("'%s' defined with more than one help text",
|
||||
current_entry->sym->name ?: "<choice>");
|
||||
}
|
||||
|
||||
/* Is the help text empty or all whitespace? */
|
||||
if ($2[strspn($2, " \f\n\r\t\v")] == '\0')
|
||||
zconfprint("warning: '%s' defined with blank help text",
|
||||
current_entry->sym->name ?: "<choice>");
|
||||
zconf_error("'%s' defined with blank help text",
|
||||
current_entry->sym->name ?: "<choice>");
|
||||
|
||||
current_entry->help = $2;
|
||||
};
|
||||
@ -598,17 +591,6 @@ static bool zconf_endtoken(const char *tokenname,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void zconfprint(const char *err, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
|
||||
va_start(ap, err);
|
||||
vfprintf(stderr, err, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void zconf_error(const char *err, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -110,7 +110,7 @@ void ConfigItem::updateMenu(void)
|
||||
|
||||
if (prop) switch (prop->type) {
|
||||
case P_MENU:
|
||||
if (list->mode == singleMode || list->mode == symbolMode) {
|
||||
if (list->mode == singleMode) {
|
||||
/* a menuconfig entry is displayed differently
|
||||
* depending whether it's at the view root or a child.
|
||||
*/
|
||||
@ -159,7 +159,7 @@ void ConfigItem::updateMenu(void)
|
||||
ch = 'M';
|
||||
break;
|
||||
default:
|
||||
if (sym_is_choice_value(sym) && type == S_BOOLEAN)
|
||||
if (sym_is_choice_value(sym))
|
||||
setIcon(promptColIdx, choiceNoIcon);
|
||||
else
|
||||
setIcon(promptColIdx, symbolNoIcon);
|
||||
@ -175,17 +175,16 @@ void ConfigItem::updateMenu(void)
|
||||
setText(dataColIdx, sym_get_string_value(sym));
|
||||
break;
|
||||
}
|
||||
if (!sym_has_value(sym) && visible)
|
||||
if (!sym_has_value(sym))
|
||||
prompt += " (NEW)";
|
||||
set_prompt:
|
||||
setText(promptColIdx, prompt);
|
||||
}
|
||||
|
||||
void ConfigItem::testUpdateMenu(bool v)
|
||||
void ConfigItem::testUpdateMenu(void)
|
||||
{
|
||||
ConfigItem* i;
|
||||
|
||||
visible = v;
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
@ -307,7 +306,6 @@ ConfigList::ConfigList(QWidget *parent, const char *name)
|
||||
{
|
||||
setObjectName(name);
|
||||
setSortingEnabled(false);
|
||||
setRootIsDecorated(true);
|
||||
|
||||
setVerticalScrollMode(ScrollPerPixel);
|
||||
setHorizontalScrollMode(ScrollPerPixel);
|
||||
@ -430,27 +428,26 @@ void ConfigList::updateList()
|
||||
item = (ConfigItem*)(*it);
|
||||
if (!item->menu)
|
||||
continue;
|
||||
item->testUpdateMenu(menu_is_visible(item->menu));
|
||||
item->testUpdateMenu();
|
||||
|
||||
++it;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rootEntry != &rootmenu && (mode == singleMode ||
|
||||
(mode == symbolMode && rootEntry->parent != &rootmenu))) {
|
||||
if (rootEntry != &rootmenu && mode == singleMode) {
|
||||
item = (ConfigItem *)topLevelItem(0);
|
||||
if (!item)
|
||||
item = new ConfigItem(this, 0, true);
|
||||
item = new ConfigItem(this, 0);
|
||||
last = item;
|
||||
}
|
||||
if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
|
||||
rootEntry->sym && rootEntry->prompt) {
|
||||
item = last ? last->nextSibling() : nullptr;
|
||||
if (!item)
|
||||
item = new ConfigItem(this, last, rootEntry, true);
|
||||
item = new ConfigItem(this, last, rootEntry);
|
||||
else
|
||||
item->testUpdateMenu(true);
|
||||
item->testUpdateMenu();
|
||||
|
||||
updateMenuList(item, rootEntry);
|
||||
update();
|
||||
@ -599,7 +596,6 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
|
||||
struct menu* child;
|
||||
ConfigItem* item;
|
||||
ConfigItem* last;
|
||||
bool visible;
|
||||
enum prop_type type;
|
||||
|
||||
if (!menu) {
|
||||
@ -631,14 +627,13 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
|
||||
break;
|
||||
}
|
||||
|
||||
visible = menu_is_visible(child);
|
||||
if (!menuSkip(child)) {
|
||||
if (!child->sym && !child->list && !child->prompt)
|
||||
continue;
|
||||
if (!item || item->menu != child)
|
||||
item = new ConfigItem(parent, last, child, visible);
|
||||
item = new ConfigItem(parent, last, child);
|
||||
else
|
||||
item->testUpdateMenu(visible);
|
||||
item->testUpdateMenu();
|
||||
|
||||
if (mode == fullMode || mode == menuMode || type != P_MENU)
|
||||
updateMenuList(item, child);
|
||||
@ -664,7 +659,6 @@ void ConfigList::updateMenuList(struct menu *menu)
|
||||
struct menu* child;
|
||||
ConfigItem* item;
|
||||
ConfigItem* last;
|
||||
bool visible;
|
||||
enum prop_type type;
|
||||
|
||||
if (!menu) {
|
||||
@ -696,14 +690,13 @@ void ConfigList::updateMenuList(struct menu *menu)
|
||||
break;
|
||||
}
|
||||
|
||||
visible = menu_is_visible(child);
|
||||
if (!menuSkip(child)) {
|
||||
if (!child->sym && !child->list && !child->prompt)
|
||||
continue;
|
||||
if (!item || item->menu != child)
|
||||
item = new ConfigItem(this, last, child, visible);
|
||||
item = new ConfigItem(this, last, child);
|
||||
else
|
||||
item->testUpdateMenu(visible);
|
||||
item->testUpdateMenu();
|
||||
|
||||
if (mode == fullMode || mode == menuMode || type != P_MENU)
|
||||
updateMenuList(item, child);
|
||||
@ -731,7 +724,7 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
|
||||
struct menu *menu;
|
||||
enum prop_type type;
|
||||
|
||||
if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
|
||||
if (ev->key() == Qt::Key_Escape && mode == singleMode) {
|
||||
emit parentSelected();
|
||||
ev->accept();
|
||||
return;
|
||||
@ -781,13 +774,6 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
|
||||
ev->accept();
|
||||
}
|
||||
|
||||
void ConfigList::mousePressEvent(QMouseEvent* e)
|
||||
{
|
||||
//QPoint p(contentsToViewport(e->pos()));
|
||||
//printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
|
||||
Parent::mousePressEvent(e);
|
||||
}
|
||||
|
||||
void ConfigList::mouseReleaseEvent(QMouseEvent* e)
|
||||
{
|
||||
QPoint p = e->pos();
|
||||
@ -834,13 +820,6 @@ skip:
|
||||
Parent::mouseReleaseEvent(e);
|
||||
}
|
||||
|
||||
void ConfigList::mouseMoveEvent(QMouseEvent* e)
|
||||
{
|
||||
//QPoint p(contentsToViewport(e->pos()));
|
||||
//printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
|
||||
Parent::mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
|
||||
{
|
||||
QPoint p = e->pos();
|
||||
@ -1022,7 +1001,7 @@ void ConfigInfoView::menuInfo(void)
|
||||
if (sym->name) {
|
||||
stream << " (";
|
||||
if (showDebug())
|
||||
stream << "<a href=\"s" << sym->name << "\">";
|
||||
stream << "<a href=\"" << sym->name << "\">";
|
||||
stream << print_filter(sym->name);
|
||||
if (showDebug())
|
||||
stream << "</a>";
|
||||
@ -1031,7 +1010,7 @@ void ConfigInfoView::menuInfo(void)
|
||||
} else if (sym->name) {
|
||||
stream << "<big><b>";
|
||||
if (showDebug())
|
||||
stream << "<a href=\"s" << sym->name << "\">";
|
||||
stream << "<a href=\"" << sym->name << "\">";
|
||||
stream << print_filter(sym->name);
|
||||
if (showDebug())
|
||||
stream << "</a>";
|
||||
@ -1086,9 +1065,9 @@ QString ConfigInfoView::debug_info(struct symbol *sym)
|
||||
switch (prop->type) {
|
||||
case P_PROMPT:
|
||||
case P_MENU:
|
||||
stream << "prompt: <a href=\"m" << sym->name << "\">";
|
||||
stream << "prompt: ";
|
||||
stream << print_filter(prop->text);
|
||||
stream << "</a><br>";
|
||||
stream << "<br>";
|
||||
break;
|
||||
case P_DEFAULT:
|
||||
case P_SELECT:
|
||||
@ -1122,28 +1101,19 @@ QString ConfigInfoView::print_filter(const QString &str)
|
||||
{
|
||||
QRegularExpression re("[<>&\"\\n]");
|
||||
QString res = str;
|
||||
|
||||
QHash<QChar, QString> patterns;
|
||||
patterns['<'] = "<";
|
||||
patterns['>'] = ">";
|
||||
patterns['&'] = "&";
|
||||
patterns['"'] = """;
|
||||
patterns['\n'] = "<br>";
|
||||
|
||||
for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
|
||||
switch (res[i].toLatin1()) {
|
||||
case '<':
|
||||
res.replace(i, 1, "<");
|
||||
i += 4;
|
||||
break;
|
||||
case '>':
|
||||
res.replace(i, 1, ">");
|
||||
i += 4;
|
||||
break;
|
||||
case '&':
|
||||
res.replace(i, 1, "&");
|
||||
i += 5;
|
||||
break;
|
||||
case '"':
|
||||
res.replace(i, 1, """);
|
||||
i += 6;
|
||||
break;
|
||||
case '\n':
|
||||
res.replace(i, 1, "<br>");
|
||||
i += 4;
|
||||
break;
|
||||
const QString n = patterns.value(res[i], QString());
|
||||
if (!n.isEmpty()) {
|
||||
res.replace(i, 1, n);
|
||||
i += n.length();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@ -1154,7 +1124,7 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
|
||||
QTextStream *stream = reinterpret_cast<QTextStream *>(data);
|
||||
|
||||
if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
|
||||
*stream << "<a href=\"s" << sym->name << "\">";
|
||||
*stream << "<a href=\"" << sym->name << "\">";
|
||||
*stream << print_filter(str);
|
||||
*stream << "</a>";
|
||||
} else {
|
||||
@ -1164,39 +1134,11 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
|
||||
|
||||
void ConfigInfoView::clicked(const QUrl &url)
|
||||
{
|
||||
QByteArray str = url.toEncoded();
|
||||
const std::size_t count = str.size();
|
||||
char *data = new char[count + 2]; // '$' + '\0'
|
||||
struct symbol **result;
|
||||
struct menu *m = NULL;
|
||||
struct menu *m;
|
||||
|
||||
if (count < 1) {
|
||||
delete[] data;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(data, str.constData(), count);
|
||||
data[count] = '\0';
|
||||
|
||||
/* Seek for exact match */
|
||||
data[0] = '^';
|
||||
strcat(data, "$");
|
||||
result = sym_re_search(data);
|
||||
if (!result) {
|
||||
delete[] data;
|
||||
return;
|
||||
}
|
||||
|
||||
sym = *result;
|
||||
|
||||
/* Seek for the menu which holds the symbol */
|
||||
for (struct property *prop = sym->prop; prop; prop = prop->next) {
|
||||
if (prop->type != P_PROMPT && prop->type != P_MENU)
|
||||
continue;
|
||||
m = prop->menu;
|
||||
break;
|
||||
}
|
||||
sym = sym_find(url.toEncoded().constData());
|
||||
|
||||
m = sym_get_prompt_menu(sym);
|
||||
if (!m) {
|
||||
/* Symbol is not visible as a menu */
|
||||
symbolInfo();
|
||||
@ -1204,9 +1146,6 @@ void ConfigInfoView::clicked(const QUrl &url)
|
||||
} else {
|
||||
emit menuSelected(m);
|
||||
}
|
||||
|
||||
free(result);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
|
||||
@ -1240,8 +1179,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
|
||||
layout2->addWidget(searchButton);
|
||||
layout1->addLayout(layout2);
|
||||
|
||||
split = new QSplitter(this);
|
||||
split->setOrientation(Qt::Vertical);
|
||||
split = new QSplitter(Qt::Vertical, this);
|
||||
list = new ConfigList(split, "search");
|
||||
list->mode = listMode;
|
||||
info = new ConfigInfoView(split, "search");
|
||||
@ -1300,8 +1238,7 @@ void ConfigSearchWindow::search(void)
|
||||
return;
|
||||
for (p = result; *p; p++) {
|
||||
for_all_prompts((*p), prop)
|
||||
lastItem = new ConfigItem(list, lastItem, prop->menu,
|
||||
menu_is_visible(prop->menu));
|
||||
lastItem = new ConfigItem(list, lastItem, prop->menu);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1341,61 +1278,56 @@ ConfigMainWindow::ConfigMainWindow(void)
|
||||
ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
|
||||
|
||||
QWidget *widget = new QWidget(this);
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
setCentralWidget(widget);
|
||||
|
||||
split1 = new QSplitter(widget);
|
||||
split1->setOrientation(Qt::Horizontal);
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
|
||||
split2 = new QSplitter(Qt::Vertical, widget);
|
||||
layout->addWidget(split2);
|
||||
split2->setChildrenCollapsible(false);
|
||||
|
||||
split1 = new QSplitter(Qt::Horizontal, split2);
|
||||
split1->setChildrenCollapsible(false);
|
||||
|
||||
menuList = new ConfigList(widget, "menu");
|
||||
configList = new ConfigList(split1, "config");
|
||||
|
||||
split2 = new QSplitter(widget);
|
||||
split2->setChildrenCollapsible(false);
|
||||
split2->setOrientation(Qt::Vertical);
|
||||
|
||||
// create config tree
|
||||
configList = new ConfigList(widget, "config");
|
||||
|
||||
helpText = new ConfigInfoView(widget, "help");
|
||||
|
||||
layout->addWidget(split2);
|
||||
split2->addWidget(split1);
|
||||
split1->addWidget(configList);
|
||||
split1->addWidget(menuList);
|
||||
split2->addWidget(helpText);
|
||||
menuList = new ConfigList(split1, "menu");
|
||||
|
||||
helpText = new ConfigInfoView(split2, "help");
|
||||
setTabOrder(configList, helpText);
|
||||
|
||||
configList->setFocus();
|
||||
|
||||
backAction = new QAction(QPixmap(xpm_back), "Back", this);
|
||||
backAction->setShortcut(QKeySequence::Back);
|
||||
connect(backAction, &QAction::triggered,
|
||||
this, &ConfigMainWindow::goBack);
|
||||
|
||||
QAction *quitAction = new QAction("&Quit", this);
|
||||
quitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
|
||||
quitAction->setShortcut(QKeySequence::Quit);
|
||||
connect(quitAction, &QAction::triggered,
|
||||
this, &ConfigMainWindow::close);
|
||||
|
||||
QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
|
||||
loadAction->setShortcut(Qt::CTRL | Qt::Key_L);
|
||||
QAction *loadAction = new QAction(QPixmap(xpm_load), "&Open", this);
|
||||
loadAction->setShortcut(QKeySequence::Open);
|
||||
connect(loadAction, &QAction::triggered,
|
||||
this, &ConfigMainWindow::loadConfig);
|
||||
|
||||
saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
|
||||
saveAction->setShortcut(Qt::CTRL | Qt::Key_S);
|
||||
saveAction->setShortcut(QKeySequence::Save);
|
||||
connect(saveAction, &QAction::triggered,
|
||||
this, &ConfigMainWindow::saveConfig);
|
||||
|
||||
conf_set_changed_callback(conf_changed);
|
||||
|
||||
configname = xstrdup(conf_get_configname());
|
||||
configname = conf_get_configname();
|
||||
|
||||
QAction *saveAsAction = new QAction("Save &As...", this);
|
||||
saveAsAction->setShortcut(QKeySequence::SaveAs);
|
||||
connect(saveAsAction, &QAction::triggered,
|
||||
this, &ConfigMainWindow::saveConfigAs);
|
||||
QAction *searchAction = new QAction("&Find", this);
|
||||
searchAction->setShortcut(Qt::CTRL | Qt::Key_F);
|
||||
searchAction->setShortcut(QKeySequence::Find);
|
||||
connect(searchAction, &QAction::triggered,
|
||||
this, &ConfigMainWindow::searchConfig);
|
||||
singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
|
||||
@ -1505,6 +1437,9 @@ ConfigMainWindow::ConfigMainWindow(void)
|
||||
connect(helpText, &ConfigInfoView::menuSelected,
|
||||
this, &ConfigMainWindow::setMenuLink);
|
||||
|
||||
connect(configApp, &QApplication::aboutToQuit,
|
||||
this, &ConfigMainWindow::saveSettings);
|
||||
|
||||
conf_read(NULL);
|
||||
|
||||
QString listMode = configSettings->value("/listMode", "symbol").toString();
|
||||
@ -1528,28 +1463,22 @@ ConfigMainWindow::ConfigMainWindow(void)
|
||||
void ConfigMainWindow::loadConfig(void)
|
||||
{
|
||||
QString str;
|
||||
QByteArray ba;
|
||||
const char *name;
|
||||
|
||||
str = QFileDialog::getOpenFileName(this, "", configname);
|
||||
if (str.isNull())
|
||||
return;
|
||||
|
||||
ba = str.toLocal8Bit();
|
||||
name = ba.data();
|
||||
|
||||
if (conf_read(name))
|
||||
if (conf_read(str.toLocal8Bit().constData()))
|
||||
QMessageBox::information(this, "qconf", "Unable to load configuration!");
|
||||
|
||||
free(configname);
|
||||
configname = xstrdup(name);
|
||||
configname = str;
|
||||
|
||||
ConfigList::updateListAllForAll();
|
||||
}
|
||||
|
||||
bool ConfigMainWindow::saveConfig(void)
|
||||
{
|
||||
if (conf_write(configname)) {
|
||||
if (conf_write(configname.toLocal8Bit().constData())) {
|
||||
QMessageBox::information(this, "qconf", "Unable to save configuration!");
|
||||
return false;
|
||||
}
|
||||
@ -1561,23 +1490,17 @@ bool ConfigMainWindow::saveConfig(void)
|
||||
void ConfigMainWindow::saveConfigAs(void)
|
||||
{
|
||||
QString str;
|
||||
QByteArray ba;
|
||||
const char *name;
|
||||
|
||||
str = QFileDialog::getSaveFileName(this, "", configname);
|
||||
if (str.isNull())
|
||||
return;
|
||||
|
||||
ba = str.toLocal8Bit();
|
||||
name = ba.data();
|
||||
|
||||
if (conf_write(name)) {
|
||||
if (conf_write(str.toLocal8Bit().constData())) {
|
||||
QMessageBox::information(this, "qconf", "Unable to save configuration!");
|
||||
}
|
||||
conf_write_autoconf(0);
|
||||
|
||||
free(configname);
|
||||
configname = xstrdup(name);
|
||||
configname = str;
|
||||
}
|
||||
|
||||
void ConfigMainWindow::searchConfig(void)
|
||||
@ -1662,9 +1585,6 @@ void ConfigMainWindow::listFocusChanged(void)
|
||||
|
||||
void ConfigMainWindow::goBack(void)
|
||||
{
|
||||
if (configList->rootEntry == &rootmenu)
|
||||
return;
|
||||
|
||||
configList->setParentMenu();
|
||||
}
|
||||
|
||||
@ -1905,8 +1825,6 @@ int main(int ac, char** av)
|
||||
v = new ConfigMainWindow();
|
||||
|
||||
//zconfdump(stdout);
|
||||
configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
|
||||
configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
|
||||
|
||||
v->show();
|
||||
configApp->exec();
|
||||
|
@ -55,9 +55,7 @@ class ConfigList : public QTreeWidget {
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||
void focusInEvent(QFocusEvent *e);
|
||||
void contextMenuEvent(QContextMenuEvent *e);
|
||||
@ -116,25 +114,25 @@ public slots:
|
||||
class ConfigItem : public QTreeWidgetItem {
|
||||
typedef class QTreeWidgetItem Parent;
|
||||
public:
|
||||
ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v)
|
||||
: Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
|
||||
ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m)
|
||||
: Parent(parent, after), nextItem(0), menu(m), goParent(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
|
||||
: Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
|
||||
ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m)
|
||||
: Parent(parent, after), nextItem(0), menu(m), goParent(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
ConfigItem(ConfigList *parent, ConfigItem *after, bool v)
|
||||
: Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true)
|
||||
ConfigItem(ConfigList *parent, ConfigItem *after)
|
||||
: Parent(parent, after), nextItem(0), menu(0), goParent(true)
|
||||
{
|
||||
init();
|
||||
}
|
||||
~ConfigItem(void);
|
||||
void init(void);
|
||||
void updateMenu(void);
|
||||
void testUpdateMenu(bool v);
|
||||
void testUpdateMenu(void);
|
||||
ConfigList* listView() const
|
||||
{
|
||||
return (ConfigList*)Parent::treeWidget();
|
||||
@ -161,7 +159,6 @@ class ConfigItem : public QTreeWidgetItem {
|
||||
|
||||
ConfigItem* nextItem;
|
||||
struct menu *menu;
|
||||
bool visible;
|
||||
bool goParent;
|
||||
|
||||
static QIcon symbolYesIcon, symbolModIcon, symbolNoIcon;
|
||||
@ -237,7 +234,7 @@ public slots:
|
||||
class ConfigMainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
char *configname;
|
||||
QString configname;
|
||||
static QAction *saveAction;
|
||||
static void conf_changed(bool);
|
||||
public:
|
||||
|
@ -144,6 +144,7 @@ my %selects;
|
||||
my %prompts;
|
||||
my %objects;
|
||||
my %config2kfile;
|
||||
my %defaults;
|
||||
my $var;
|
||||
my $iflevel = 0;
|
||||
my @ifdeps;
|
||||
@ -220,8 +221,9 @@ sub read_kconfig {
|
||||
$depends{$config} = $1;
|
||||
} elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
|
||||
$depends{$config} .= " " . $1;
|
||||
} elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
|
||||
} elsif ($state ne "NONE" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
|
||||
my $dep = $3;
|
||||
$defaults{$config} = 1;
|
||||
if ($dep !~ /^\s*(y|m|n)\s*$/) {
|
||||
$dep =~ s/.*\sif\s+//;
|
||||
$depends{$config} .= " " . $dep;
|
||||
@ -503,7 +505,7 @@ sub parse_config_selects
|
||||
|
||||
# Check if something other than a module selects this config
|
||||
if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
|
||||
dprint "$conf (non module) selects config, we are good\n";
|
||||
dprint "$conf (non module) selects $config, we are good\n";
|
||||
# we are good with this
|
||||
return;
|
||||
}
|
||||
@ -523,8 +525,16 @@ sub parse_config_selects
|
||||
|
||||
# If no possible config selected this, then something happened.
|
||||
if (!defined($next_config)) {
|
||||
print STDERR "WARNING: $config is required, but nothing in the\n";
|
||||
print STDERR " current config selects it.\n";
|
||||
|
||||
# Some config options have no prompt, and nothing selects them, but
|
||||
# they stay turned on once the final checks for the configs
|
||||
# are done. These configs have a default option, so turn off the
|
||||
# warnings for configs with default options.
|
||||
if (!defined($defaults{$config})) {
|
||||
print STDERR "WARNING: $config is required, but nothing in the\n";
|
||||
print STDERR " current config selects it.\n";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,24 @@ const char *sym_type_name(enum symbol_type type)
|
||||
return "???";
|
||||
}
|
||||
|
||||
/**
|
||||
* sym_get_prompt_menu - get the menu entry with a prompt
|
||||
*
|
||||
* @sym: a symbol pointer
|
||||
*
|
||||
* Return: the menu entry with a prompt.
|
||||
*/
|
||||
struct menu *sym_get_prompt_menu(const struct symbol *sym)
|
||||
{
|
||||
struct menu *m;
|
||||
|
||||
list_for_each_entry(m, &sym->menus, link)
|
||||
if (m->prompt)
|
||||
return m;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sym_get_choice_menu - get the parent choice menu if present
|
||||
*
|
||||
@ -80,18 +98,12 @@ const char *sym_type_name(enum symbol_type type)
|
||||
struct menu *sym_get_choice_menu(const struct symbol *sym)
|
||||
{
|
||||
struct menu *menu = NULL;
|
||||
struct menu *m;
|
||||
|
||||
/*
|
||||
* Choice members must have a prompt. Find a menu entry with a prompt,
|
||||
* and assume it resides inside a choice block.
|
||||
*/
|
||||
list_for_each_entry(m, &sym->menus, link)
|
||||
if (m->prompt) {
|
||||
menu = m;
|
||||
break;
|
||||
}
|
||||
|
||||
menu = sym_get_prompt_menu(sym);
|
||||
if (!menu)
|
||||
return NULL;
|
||||
|
||||
|
@ -68,6 +68,10 @@ vmlinux_link()
|
||||
libs="${KBUILD_VMLINUX_LIBS}"
|
||||
fi
|
||||
|
||||
if is_enabled CONFIG_GENERIC_BUILTIN_DTB; then
|
||||
objs="${objs} .builtin-dtbs.o"
|
||||
fi
|
||||
|
||||
if is_enabled CONFIG_MODULES; then
|
||||
objs="${objs} .vmlinux.export.o"
|
||||
fi
|
||||
@ -208,8 +212,8 @@ kallsymso=
|
||||
strip_debug=
|
||||
|
||||
if is_enabled CONFIG_KALLSYMS; then
|
||||
true > .tmp_vmlinux.kallsyms0.syms
|
||||
kallsyms .tmp_vmlinux.kallsyms0.syms .tmp_vmlinux0.kallsyms
|
||||
true > .tmp_vmlinux0.syms
|
||||
kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms
|
||||
fi
|
||||
|
||||
if is_enabled CONFIG_KALLSYMS || is_enabled CONFIG_DEBUG_INFO_BTF; then
|
||||
@ -236,14 +240,14 @@ if is_enabled CONFIG_KALLSYMS; then
|
||||
# Generate section listing all symbols and add it into vmlinux
|
||||
# It's a four step process:
|
||||
# 0) Generate a dummy __kallsyms with empty symbol list.
|
||||
# 1) Link .tmp_vmlinux.kallsyms1 so it has all symbols and sections,
|
||||
# 1) Link .tmp_vmlinux1.kallsyms so it has all symbols and sections,
|
||||
# with a dummy __kallsyms.
|
||||
# Running kallsyms on that gives us .tmp_kallsyms1.o with
|
||||
# Running kallsyms on that gives us .tmp_vmlinux1.kallsyms.o with
|
||||
# the right size
|
||||
# 2) Link .tmp_vmlinux.kallsyms2 so it now has a __kallsyms section of
|
||||
# 2) Link .tmp_vmlinux2.kallsyms so it now has a __kallsyms section of
|
||||
# the right size, but due to the added section, some
|
||||
# addresses have shifted.
|
||||
# From here, we generate a correct .tmp_vmlinux.kallsyms2.o
|
||||
# From here, we generate a correct .tmp_vmlinux2.kallsyms.o
|
||||
# 3) That link may have expanded the kernel image enough that
|
||||
# more linker branch stubs / trampolines had to be added, which
|
||||
# introduces new names, which further expands kallsyms. Do another
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <hash.h>
|
||||
#include <hashtable.h>
|
||||
#include <list.h>
|
||||
#include <xalloc.h>
|
||||
@ -176,6 +177,7 @@ static struct module *new_module(const char *name, size_t namelen)
|
||||
INIT_LIST_HEAD(&mod->unresolved_symbols);
|
||||
INIT_LIST_HEAD(&mod->missing_namespaces);
|
||||
INIT_LIST_HEAD(&mod->imported_namespaces);
|
||||
INIT_LIST_HEAD(&mod->aliases);
|
||||
|
||||
memcpy(mod->name, name, namelen);
|
||||
mod->name[namelen] = '\0';
|
||||
@ -209,19 +211,6 @@ struct symbol {
|
||||
|
||||
static HASHTABLE_DEFINE(symbol_hashtable, 1U << 10);
|
||||
|
||||
/* This is based on the hash algorithm from gdbm, via tdb */
|
||||
static inline unsigned int tdb_hash(const char *name)
|
||||
{
|
||||
unsigned value; /* Used to compute the hash value. */
|
||||
unsigned i; /* Used to cycle through random values. */
|
||||
|
||||
/* Set the initial value from the key size. */
|
||||
for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
|
||||
value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
|
||||
|
||||
return (1103515243 * value + 12345);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new symbols for use in the hash of exported symbols or
|
||||
* the list of unresolved symbols per module
|
||||
@ -239,7 +228,7 @@ static struct symbol *alloc_symbol(const char *name)
|
||||
/* For the hash of exported symbols */
|
||||
static void hash_add_symbol(struct symbol *sym)
|
||||
{
|
||||
hash_add(symbol_hashtable, &sym->hnode, tdb_hash(sym->name));
|
||||
hash_add(symbol_hashtable, &sym->hnode, hash_str(sym->name));
|
||||
}
|
||||
|
||||
static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
|
||||
@ -260,7 +249,7 @@ static struct symbol *sym_find_with_module(const char *name, struct module *mod)
|
||||
if (name[0] == '.')
|
||||
name++;
|
||||
|
||||
hash_for_each_possible(symbol_hashtable, s, hnode, tdb_hash(name)) {
|
||||
hash_for_each_possible(symbol_hashtable, s, hnode, hash_str(name)) {
|
||||
if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
|
||||
return s;
|
||||
}
|
||||
@ -340,8 +329,6 @@ static const char *sec_name(const struct elf_info *info, unsigned int secindex)
|
||||
return sech_name(info, &info->sechdrs[secindex]);
|
||||
}
|
||||
|
||||
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
|
||||
|
||||
static struct symbol *sym_add_exported(const char *name, struct module *mod,
|
||||
bool gpl_only, const char *namespace)
|
||||
{
|
||||
@ -1966,6 +1953,7 @@ static void write_vmlinux_export_c_file(struct module *mod)
|
||||
static void write_mod_c_file(struct module *mod)
|
||||
{
|
||||
struct buffer buf = { };
|
||||
struct module_alias *alias, *next;
|
||||
char fname[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
@ -1973,7 +1961,14 @@ static void write_mod_c_file(struct module *mod)
|
||||
add_exported_symbols(&buf, mod);
|
||||
add_versions(&buf, mod);
|
||||
add_depends(&buf, mod);
|
||||
add_moddevtable(&buf, mod);
|
||||
|
||||
buf_printf(&buf, "\n");
|
||||
list_for_each_entry_safe(alias, next, &mod->aliases, node) {
|
||||
buf_printf(&buf, "MODULE_ALIAS(\"%s\");\n", alias->str);
|
||||
list_del(&alias->node);
|
||||
free(alias);
|
||||
}
|
||||
|
||||
add_srcversion(&buf, mod);
|
||||
|
||||
ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
|
||||
|
@ -67,6 +67,8 @@
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
|
||||
|
||||
struct buffer {
|
||||
char *p;
|
||||
int pos;
|
||||
@ -79,6 +81,22 @@ buf_printf(struct buffer *buf, const char *fmt, ...);
|
||||
void
|
||||
buf_write(struct buffer *buf, const char *s, int len);
|
||||
|
||||
/**
|
||||
* struct module_alias - auto-generated MODULE_ALIAS()
|
||||
*
|
||||
* @node: linked to module::aliases
|
||||
* @str: a string for MODULE_ALIAS()
|
||||
*/
|
||||
struct module_alias {
|
||||
struct list_head node;
|
||||
char str[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct module - represent a module (vmlinux or *.ko)
|
||||
*
|
||||
* @aliases: list head for module_aliases
|
||||
*/
|
||||
struct module {
|
||||
struct list_head list;
|
||||
struct list_head exported_symbols;
|
||||
@ -89,12 +107,12 @@ struct module {
|
||||
bool seen;
|
||||
bool has_init;
|
||||
bool has_cleanup;
|
||||
struct buffer dev_table_buf;
|
||||
char srcversion[25];
|
||||
// Missing namespace dependencies
|
||||
struct list_head missing_namespaces;
|
||||
// Actual imported namespaces
|
||||
struct list_head imported_namespaces;
|
||||
struct list_head aliases;
|
||||
char name[];
|
||||
};
|
||||
|
||||
@ -170,7 +188,6 @@ Elf_Sym *symsearch_find_nearest(struct elf_info *elf, Elf_Addr addr,
|
||||
/* file2alias.c */
|
||||
void handle_moddevtable(struct module *mod, struct elf_info *info,
|
||||
Elf_Sym *sym, const char *symname);
|
||||
void add_moddevtable(struct buffer *buf, struct module *mod);
|
||||
|
||||
/* sumversion.c */
|
||||
void get_src_version(const char *modname, char sum[], unsigned sumlen);
|
||||
|
@ -19,12 +19,6 @@ if ! { echo "$SPATCH_REQ_VERSION"; echo "$SPATCH_VERSION"; } | sort -CV ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$KBUILD_EXTMOD" ]; then
|
||||
src_prefix=
|
||||
else
|
||||
src_prefix=$srctree/
|
||||
fi
|
||||
|
||||
generate_deps_for_ns() {
|
||||
$SPATCH --very-quiet --in-place --sp-file \
|
||||
$srctree/scripts/coccinelle/misc/add_namespace.cocci -D nsdeps -D ns=$1 $2
|
||||
@ -34,7 +28,7 @@ generate_deps() {
|
||||
local mod=${1%.ko:}
|
||||
shift
|
||||
local namespaces="$*"
|
||||
local mod_source_files=$(sed "s|^\(.*\)\.o$|${src_prefix}\1.c|" $mod.mod)
|
||||
local mod_source_files=$(sed "s|^\(.*\)\.o$|${srcroot}/\1.c|" $mod.mod)
|
||||
|
||||
for ns in $namespaces; do
|
||||
echo "Adding namespace $ns to module $mod.ko."
|
||||
@ -57,4 +51,4 @@ generate_deps() {
|
||||
while read line
|
||||
do
|
||||
generate_deps $line
|
||||
done < $MODULES_NSDEPS
|
||||
done < modules.nsdeps
|
||||
|
@ -96,16 +96,18 @@ install_linux_image_dbg () {
|
||||
|
||||
# Parse modules.order directly because 'make modules_install' may sign,
|
||||
# compress modules, and then run unneeded depmod.
|
||||
while read -r mod; do
|
||||
mod="${mod%.o}.ko"
|
||||
dbg="${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/kernel/${mod}"
|
||||
buildid=$("${READELF}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p')
|
||||
link="${pdir}/usr/lib/debug/.build-id/${buildid}.debug"
|
||||
if is_enabled CONFIG_MODULES; then
|
||||
while read -r mod; do
|
||||
mod="${mod%.o}.ko"
|
||||
dbg="${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/kernel/${mod}"
|
||||
buildid=$("${READELF}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p')
|
||||
link="${pdir}/usr/lib/debug/.build-id/${buildid}.debug"
|
||||
|
||||
mkdir -p "${dbg%/*}" "${link%/*}"
|
||||
"${OBJCOPY}" --only-keep-debug "${mod}" "${dbg}"
|
||||
ln -sf --relative "${dbg}" "${link}"
|
||||
done < modules.order
|
||||
mkdir -p "${dbg%/*}" "${link%/*}"
|
||||
"${OBJCOPY}" --only-keep-debug "${mod}" "${dbg}"
|
||||
ln -sf --relative "${dbg}" "${link}"
|
||||
done < modules.order
|
||||
fi
|
||||
|
||||
# Build debug package
|
||||
# Different tools want the image in different locations
|
||||
|
@ -51,6 +51,13 @@ mkdir -p "${destdir}"
|
||||
if [ "${CC}" != "${HOSTCC}" ]; then
|
||||
echo "Rebuilding host programs with ${CC}..."
|
||||
|
||||
# This leverages external module building.
|
||||
# - Clear sub_make_done to allow the top-level Makefile to redo sub-make.
|
||||
# - Filter out --no-print-directory to print "Entering directory" logs
|
||||
# when Make changes the working directory.
|
||||
unset sub_make_done
|
||||
MAKEFLAGS=$(echo "${MAKEFLAGS}" | sed s/--no-print-directory//)
|
||||
|
||||
cat <<-'EOF' > "${destdir}/Kbuild"
|
||||
subdir-y := scripts
|
||||
EOF
|
||||
|
@ -202,7 +202,7 @@ Build-Depends-Arch: bc, bison, cpio, flex,
|
||||
gcc-${host_gnu} <!pkg.${sourcename}.nokernelheaders>,
|
||||
kmod, libelf-dev:native,
|
||||
libssl-dev:native, libssl-dev <!pkg.${sourcename}.nokernelheaders>,
|
||||
rsync
|
||||
python3:native, rsync
|
||||
Homepage: https://www.kernel.org/
|
||||
|
||||
Package: $packagename-$version
|
||||
|
@ -10,6 +10,8 @@
|
||||
#
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [--no-local] [srctree]" >&2
|
||||
exit 1
|
||||
@ -30,6 +32,29 @@ if test $# -gt 0 -o ! -d "$srctree"; then
|
||||
usage
|
||||
fi
|
||||
|
||||
try_tag() {
|
||||
tag="$1"
|
||||
|
||||
# Is $tag an annotated tag?
|
||||
if [ "$(git cat-file -t "$tag" 2> /dev/null)" != tag ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Is it an ancestor of HEAD, and if so, how many commits are in $tag..HEAD?
|
||||
# shellcheck disable=SC2046 # word splitting is the point here
|
||||
set -- $(git rev-list --count --left-right "$tag"...HEAD 2> /dev/null)
|
||||
|
||||
# $1 is 0 if and only if $tag is an ancestor of HEAD. Use
|
||||
# string comparison, because $1 is empty if the 'git rev-list'
|
||||
# command somehow failed.
|
||||
if [ "$1" != 0 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# $2 is the number of commits in the range $tag..HEAD, possibly 0.
|
||||
count="$2"
|
||||
}
|
||||
|
||||
scm_version()
|
||||
{
|
||||
local short=false
|
||||
@ -61,33 +86,33 @@ scm_version()
|
||||
# stable kernel: 6.1.7 -> v6.1.7
|
||||
version_tag=v$(echo "${KERNELVERSION}" | sed -E 's/^([0-9]+\.[0-9]+)\.0(.*)$/\1\2/')
|
||||
|
||||
# try_tag initializes count if the tag is usable.
|
||||
count=
|
||||
|
||||
# If a localversion* file exists, and the corresponding
|
||||
# annotated tag exists and is an ancestor of HEAD, use
|
||||
# it. This is the case in linux-next.
|
||||
tag=${file_localversion#-}
|
||||
desc=
|
||||
if [ -n "${tag}" ]; then
|
||||
desc=$(git describe --match=$tag 2>/dev/null)
|
||||
if [ -n "${file_localversion#-}" ] ; then
|
||||
try_tag "${file_localversion#-}"
|
||||
fi
|
||||
|
||||
# Otherwise, if a localversion* file exists, and the tag
|
||||
# obtained by appending it to the tag derived from
|
||||
# KERNELVERSION exists and is an ancestor of HEAD, use
|
||||
# it. This is e.g. the case in linux-rt.
|
||||
if [ -z "${desc}" ] && [ -n "${file_localversion}" ]; then
|
||||
tag="${version_tag}${file_localversion}"
|
||||
desc=$(git describe --match=$tag 2>/dev/null)
|
||||
if [ -z "${count}" ] && [ -n "${file_localversion}" ]; then
|
||||
try_tag "${version_tag}${file_localversion}"
|
||||
fi
|
||||
|
||||
# Otherwise, default to the annotated tag derived from KERNELVERSION.
|
||||
if [ -z "${desc}" ]; then
|
||||
tag="${version_tag}"
|
||||
desc=$(git describe --match=$tag 2>/dev/null)
|
||||
if [ -z "${count}" ]; then
|
||||
try_tag "${version_tag}"
|
||||
fi
|
||||
|
||||
# If we are at the tagged commit, we ignore it because the version is
|
||||
# well-defined.
|
||||
if [ "${tag}" != "${desc}" ]; then
|
||||
# If we are at the tagged commit, we ignore it because the
|
||||
# version is well-defined. If none of the attempted tags exist
|
||||
# or were usable, $count is still empty.
|
||||
if [ -z "${count}" ] || [ "${count}" -gt 0 ]; then
|
||||
|
||||
# If only the short version is requested, don't bother
|
||||
# running further git commands
|
||||
@ -95,14 +120,15 @@ scm_version()
|
||||
echo "+"
|
||||
return
|
||||
fi
|
||||
|
||||
# If we are past the tagged commit, we pretty print it.
|
||||
# (like 6.1.0-14595-g292a089d78d3)
|
||||
if [ -n "${desc}" ]; then
|
||||
echo "${desc}" | awk -F- '{printf("-%05d", $(NF-1))}'
|
||||
if [ -n "${count}" ]; then
|
||||
printf "%s%05d" "-" "${count}"
|
||||
fi
|
||||
|
||||
# Add -g and exactly 12 hex chars.
|
||||
printf '%s%s' -g "$(echo $head | cut -c1-12)"
|
||||
printf '%s%.12s' -g "$head"
|
||||
fi
|
||||
|
||||
if ${no_dirty}; then
|
||||
|
@ -4573,6 +4573,8 @@ static int validate_ibt(struct objtool_file *file)
|
||||
!strcmp(sec->name, "__jump_table") ||
|
||||
!strcmp(sec->name, "__mcount_loc") ||
|
||||
!strcmp(sec->name, ".kcfi_traps") ||
|
||||
!strcmp(sec->name, ".llvm.call-graph-profile") ||
|
||||
!strcmp(sec->name, ".llvm_bb_addr_map") ||
|
||||
!strcmp(sec->name, "__tracepoints") ||
|
||||
strstr(sec->name, "__patchable_function_entries"))
|
||||
continue;
|
||||
|
@ -224,12 +224,17 @@ int find_symbol_hole_containing(const struct section *sec, unsigned long offset)
|
||||
if (n)
|
||||
return 0; /* not a hole */
|
||||
|
||||
/* didn't find a symbol for which @offset is after it */
|
||||
if (!hole.sym)
|
||||
return 0; /* not a hole */
|
||||
/*
|
||||
* @offset >= sym->offset + sym->len, find symbol after it.
|
||||
* When hole.sym is empty, use the first node to compute the hole.
|
||||
* If there is no symbol in the section, the first node will be NULL,
|
||||
* in which case, -1 is returned to skip the whole section.
|
||||
*/
|
||||
if (hole.sym)
|
||||
n = rb_next(&hole.sym->node);
|
||||
else
|
||||
n = rb_first_cached(&sec->symbol_tree);
|
||||
|
||||
/* @offset >= sym->offset + sym->len, find symbol after it */
|
||||
n = rb_next(&hole.sym->node);
|
||||
if (!n)
|
||||
return -1; /* until end of address space */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user