.gitignore | 1 + Makefile | 2 +- rust/Makefile | 21 ++++++++++++--------- scripts/generate_rust_analyzer.py | 16 ++++++++++++---- 4 files changed, 26 insertions(+), 14 deletions(-)
Rust proc-macro crates are loaded by the compiler at compile-time, so
are always dynamic libraries; on macOS, these artifacts get a .dylib
extension rather than .so.
Replace hardcoded paths ending in .so with paths obtained from the
compiler.
Signed-off-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
.gitignore | 1 +
Makefile | 2 +-
rust/Makefile | 21 ++++++++++++---------
scripts/generate_rust_analyzer.py | 16 ++++++++++++----
4 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/.gitignore b/.gitignore
index 56972adb5031..7cfe4f70b39a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
*.dtb.S
*.dtbo.S
*.dwo
+*.dylib
*.elf
*.gcno
*.gcda
diff --git a/Makefile b/Makefile
index c5493c0c0ca1..3808869fb95b 100644
--- a/Makefile
+++ b/Makefile
@@ -1506,7 +1506,7 @@ MRPROPER_FILES += include/config include/generated \
certs/x509.genkey \
vmlinux-gdb.py \
rpmbuild \
- rust/libmacros.so
+ rust/libmacros.so rust/libmacros.dylib
# clean - Delete most, but leave enough to build external modules
#
diff --git a/rust/Makefile b/rust/Makefile
index b5e0a73b78f3..a185a4d05b08 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -11,9 +11,6 @@ always-$(CONFIG_RUST) += exports_core_generated.h
obj-$(CONFIG_RUST) += helpers/helpers.o
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
-always-$(CONFIG_RUST) += libmacros.so
-no-clean-files += libmacros.so
-
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
always-$(CONFIG_RUST) += exports_alloc_generated.h exports_helpers_generated.h \
@@ -36,9 +33,15 @@ always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
-# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
+# Avoids running `$(RUSTC)` when it may not be available.
ifdef CONFIG_RUST
+libmacros_name := $($(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - < /dev/null)
+libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name))
+
+always-$(CONFIG_RUST) += $(libmacros_name)
+no-clean-files += $(libmacros_name)
+
# `$(rust_flags)` is passed in case the user added `--sysroot`.
rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
rustc_host_target := $(shell $(RUSTC) --version --verbose | grep -F 'host: ' | cut -d' ' -f2)
@@ -115,10 +118,10 @@ rustdoc-alloc: $(RUST_LIB_SRC)/alloc/src/lib.rs rustdoc-core rustdoc-compiler_bu
+$(call if_changed,rustdoc)
rustdoc-kernel: private rustc_target_flags = --extern alloc \
- --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
+ --extern build_error --extern macros=$(objtree)/$(obj)/$(libmacros_name) \
--extern bindings --extern uapi
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
- rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
+ rustdoc-compiler_builtins rustdoc-alloc $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
+$(call if_changed,rustdoc)
@@ -339,10 +342,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
-Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro \
- --crate-name $(patsubst lib%.so,%,$(notdir $@)) $<
+ --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) $<
# Procedural macros can only be used with the `rustc` that compiled it.
-$(obj)/libmacros.so: $(src)/macros/lib.rs FORCE
+$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacro)
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
@@ -421,7 +424,7 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
--extern build_error --extern macros --extern bindings --extern uapi
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
- $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
+ $(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE
+$(call if_changed_rule,rustc_library)
endif # CONFIG_RUST
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index d2bc63cde8c6..3834ab0eea9d 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -9,6 +9,8 @@ import logging
import os
import pathlib
import sys
+import os
+import subprocess
def args_crates_cfgs(cfgs):
crates_cfgs = {}
@@ -35,8 +37,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
crates_cfgs = args_crates_cfgs(cfgs)
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
- crates_indexes[display_name] = len(crates)
- crates.append({
+ crate = {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
@@ -47,7 +48,15 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
- })
+ }
+ if is_proc_macro:
+ proc_macro_dylib_name = subprocess.check_output(
+ [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
+ stdin=subprocess.DEVNULL,
+ ).decode('utf-8')
+ crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
+ crates_indexes[display_name] = len(crates)
+ crates.append(crate)
# First, the ones in `rust/` since they are a bit special.
append_crate(
@@ -77,7 +86,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
[],
is_proc_macro=True,
)
- crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so"
append_crate(
"build_error",
--
2.47.0
On Wed Oct 9, 2024 at 12:48 AM CEST, Tamir Duberstein wrote: > Rust proc-macro crates are loaded by the compiler at compile-time, so > are always dynamic libraries; on macOS, these artifacts get a .dylib > extension rather than .so. > > Replace hardcoded paths ending in .so with paths obtained from the > compiler. > > Signed-off-by: Fiona Behrens <me@kloenk.dev> > Signed-off-by: Tamir Duberstein <tamird@gmail.com> > --- > .gitignore | 1 + > Makefile | 2 +- > rust/Makefile | 21 ++++++++++++--------- > scripts/generate_rust_analyzer.py | 16 ++++++++++++---- > 4 files changed, 26 insertions(+), 14 deletions(-) > > diff --git a/.gitignore b/.gitignore > index 56972adb5031..7cfe4f70b39a 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -22,6 +22,7 @@ > *.dtb.S > *.dtbo.S > *.dwo > +*.dylib > *.elf > *.gcno > *.gcda > diff --git a/Makefile b/Makefile > index c5493c0c0ca1..3808869fb95b 100644 > --- a/Makefile > +++ b/Makefile > @@ -1506,7 +1506,7 @@ MRPROPER_FILES += include/config include/generated \ > certs/x509.genkey \ > vmlinux-gdb.py \ > rpmbuild \ > - rust/libmacros.so > + rust/libmacros.so rust/libmacros.dylib > > # clean - Delete most, but leave enough to build external modules > # > diff --git a/rust/Makefile b/rust/Makefile > index b5e0a73b78f3..a185a4d05b08 100644 > --- a/rust/Makefile > +++ b/rust/Makefile > @@ -11,9 +11,6 @@ always-$(CONFIG_RUST) += exports_core_generated.h > obj-$(CONFIG_RUST) += helpers/helpers.o > CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations > > -always-$(CONFIG_RUST) += libmacros.so > -no-clean-files += libmacros.so > - > always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs > obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o > always-$(CONFIG_RUST) += exports_alloc_generated.h exports_helpers_generated.h \ > @@ -36,9 +33,15 @@ always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c > obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o > obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o > > -# Avoids running `$(RUSTC)` for the sysroot when it may not be available. > +# Avoids running `$(RUSTC)` when it may not be available. > ifdef CONFIG_RUST > > +libmacros_name := $($(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - < /dev/null) > +libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name)) > + > +always-$(CONFIG_RUST) += $(libmacros_name) > +no-clean-files += $(libmacros_name) > + > # `$(rust_flags)` is passed in case the user added `--sysroot`. > rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot) > rustc_host_target := $(shell $(RUSTC) --version --verbose | grep -F 'host: ' | cut -d' ' -f2) > @@ -115,10 +118,10 @@ rustdoc-alloc: $(RUST_LIB_SRC)/alloc/src/lib.rs rustdoc-core rustdoc-compiler_bu > +$(call if_changed,rustdoc) > > rustdoc-kernel: private rustc_target_flags = --extern alloc \ > - --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \ > + --extern build_error --extern macros=$(objtree)/$(obj)/$(libmacros_name) \ > --extern bindings --extern uapi > rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \ > - rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \ > + rustdoc-compiler_builtins rustdoc-alloc $(obj)/$(libmacros_name) \ > $(obj)/bindings.o FORCE > +$(call if_changed,rustdoc) > > @@ -339,10 +342,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@ > -Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \ > --emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \ > --crate-type proc-macro \ > - --crate-name $(patsubst lib%.so,%,$(notdir $@)) $< > + --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) $< > > # Procedural macros can only be used with the `rustc` that compiled it. > -$(obj)/libmacros.so: $(src)/macros/lib.rs FORCE > +$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE > +$(call if_changed_dep,rustc_procmacro) > > quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@ > @@ -421,7 +424,7 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \ > $(obj)/kernel.o: private rustc_target_flags = --extern alloc \ > --extern build_error --extern macros --extern bindings --extern uapi > $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \ > - $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE > + $(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE > +$(call if_changed_rule,rustc_library) > > endif # CONFIG_RUST > diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py > index d2bc63cde8c6..3834ab0eea9d 100755 > --- a/scripts/generate_rust_analyzer.py > +++ b/scripts/generate_rust_analyzer.py > @@ -9,6 +9,8 @@ import logging > import os > import pathlib > import sys > +import os > +import subprocess import os is duplicated. > > def args_crates_cfgs(cfgs): > crates_cfgs = {} > @@ -35,8 +37,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): > crates_cfgs = args_crates_cfgs(cfgs) > > def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False): > - crates_indexes[display_name] = len(crates) > - crates.append({ > + crate = { > "display_name": display_name, > "root_module": str(root_module), > "is_workspace_member": is_workspace_member, > @@ -47,7 +48,15 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): > "env": { > "RUST_MODFILE": "This is only for rust-analyzer" > } > - }) > + } > + if is_proc_macro: > + proc_macro_dylib_name = subprocess.check_output( > + [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"], > + stdin=subprocess.DEVNULL, > + ).decode('utf-8') > + crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}" > + crates_indexes[display_name] = len(crates) > + crates.append(crate) > > # First, the ones in `rust/` since they are a bit special. > append_crate( > @@ -77,7 +86,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): > [], > is_proc_macro=True, > ) > - crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so" > > append_crate( > "build_error",
On Wed, Oct 9, 2024 at 12:48 AM Tamir Duberstein <tamird@gmail.com> wrote: > > Rust proc-macro crates are loaded by the compiler at compile-time, so > are always dynamic libraries; on macOS, these artifacts get a .dylib > extension rather than .so. What is the status of the macOS build support? A link would be nice here. > Signed-off-by: Fiona Behrens <me@kloenk.dev> Is this patch Fiona's/yours/both? Depending on that, different tags are needed here (including `From:`). Please see: https://docs.kernel.org/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by > @@ -9,6 +9,8 @@ import logging > import os > import pathlib > import sys > +import os > +import subprocess Nit: double import, unsorted. Thanks! Cheers, Miguel
On Wed, Oct 9, 2024 at 8:43 AM Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > On Wed, Oct 9, 2024 at 12:48 AM Tamir Duberstein <tamird@gmail.com> wrote: > > > > Rust proc-macro crates are loaded by the compiler at compile-time, so > > are always dynamic libraries; on macOS, these artifacts get a .dylib > > extension rather than .so. > > What is the status of the macOS build support? A link would be nice here. What would you have me link to? With this patch applied and using https://github.com/bee-headers/homebrew-bee-headers I was able to build a kernel on my apple silicon mac. Relevant config: tamird@Tamirs-MBP linux % rg -N '_RUST' .config CONFIG_RUSTC_VERSION=108100 CONFIG_RUST_IS_AVAILABLE=y CONFIG_RUST=y CONFIG_RUSTC_VERSION_TEXT="rustc 1.81.0 (eeb90cda1 2024-09-04)" CONFIG_RUSTC_SUPPORTS_ARM64=y CONFIG_HAVE_RUST=y # CONFIG_RUST_FW_LOADER_ABSTRACTIONS is not set # CONFIG_BLK_DEV_RUST_NULL is not set # CONFIG_RUST_PHYLIB_ABSTRACTIONS is not set CONFIG_SAMPLES_RUST=y CONFIG_SAMPLE_RUST_MINIMAL=m CONFIG_SAMPLE_RUST_PRINT=m CONFIG_SAMPLE_RUST_HOSTPROGS=y CONFIG_RUST_DEBUG_ASSERTIONS=y CONFIG_RUST_OVERFLOW_CHECKS=y # CONFIG_RUST_BUILD_ASSERT_ALLOW is not set > > Signed-off-by: Fiona Behrens <me@kloenk.dev> > > Is this patch Fiona's/yours/both? Depending on that, different tags > are needed here (including `From:`). Please see: > > https://docs.kernel.org/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by Thanks. Fiona wrote the original patch ~2 years ago. I rebased it and generalized it some. I'll use Co-developed-by. > > @@ -9,6 +9,8 @@ import logging > > import os > > import pathlib > > import sys > > +import os > > +import subprocess > > Nit: double import, unsorted. Ack, will fix. > > Thanks! > > Cheers, > Miguel
On Wed, Oct 9, 2024 at 2:57 PM Tamir Duberstein <tamird@gmail.com> wrote: > > What would you have me link to? With this patch applied and using I was thinking perhaps the series from Daniel, if that is the latest discussion (?), i.e. I would like to understand what is the policy around changes like this, what happens if it breaks, etc. > https://github.com/bee-headers/homebrew-bee-headers I was able to build a kernel > on my apple silicon mac. Relevant config: That is great. Thanks! Cheers, Miguel
On Wed Oct 9, 2024 at 3:12 PM CEST, Miguel Ojeda wrote: > On Wed, Oct 9, 2024 at 2:57 PM Tamir Duberstein <tamird@gmail.com> wrote: >> >> What would you have me link to? With this patch applied and using > > I was thinking perhaps the series from Daniel, if that is the latest > discussion (?), i.e. I would like to understand what is the policy > around changes like this, what happens if it breaks, etc. Building Linux in macOS is now supported for arm64 (targets tested: allyesconfig and defconfig). The upstream policy is to use the build system variables to configure the necessary tweaks to support building in macOS. However, this will not always be possible then, patches are welcome from the build system maintainer to support "portability" across OSes. But not full integration. Please, let me know if this is not clear. This policy forces macOS users to provide their own environment, documentation and dependencies. I created bee-headers with the intention of providing all this (including the missing byteswap, elf and endian headers) as reference or for developers to use. So, after installing bee-headers and all other linux dependencies (llvm, sed, awk, etc), one would simply do: source bee-init # To initiate the build enviroment make LLVM=1 defconfig make LLVM=1 -j$(nproc) Here a more detailed documentation: https://github.com/bee-headers/homebrew-bee-headers/blob/main/README.md The last version of the series is v3 [1], which fixes a build error that cannot be fixed in macOS via build system environment. This is enabled when using Intel Xe Graphics (DRM_XE), included in allyesconfig target. [1] https://lore.kernel.org/all/20240925-macos-build-support-v3-1-233dda880e60@samsung.com/ > >> https://github.com/bee-headers/homebrew-bee-headers I was able to build a kernel >> on my apple silicon mac. Relevant config: > > That is great. > > Thanks! > > Cheers, > Miguel
On Thu, Oct 10, 2024 at 10:31 AM Daniel Gomez <da.gomez@samsung.com> wrote: > > Building Linux in macOS is now supported for arm64 (targets tested: allyesconfig > and defconfig). The upstream policy is to use the build system variables to > configure the necessary tweaks to support building in macOS. However, this > will not always be possible then, patches are welcome from the build system > maintainer to support "portability" across OSes. But not full integration. > Please, let me know if this is not clear. Thanks for writing this -- it seems similar to the summary you wrote elsewhere, but it does confirm we should probably be using build variables instead (i.e. I don't think the overall macOS support questions are answered, but we don't need to answer them here). In other words, it sounds to me like the solution here is to simply provide a variable with the current name as the default, and let out-of-tree override that if they need, rather than query `rustc`. Thus upstream can keep the variable working very easily, and out-of-tree can maintain/test the overall macOS support. Does that sound reasonable for everyone? Cheers, Miguel
On Sat, Oct 12, 2024, 09:41 Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > In other words, it sounds to me like the solution here is to simply > provide a variable with the current name as the default, and let > out-of-tree override that if they need, rather than query `rustc`. In order for this to be reasonably maintainable we'd want the variable to be something like DYLIB_SUFFIX so that we don't have to revisit this if macros are ever provided by more than one crate (or worse, have to provide N variables). If this is the preferred path, I can rework this patch in that direction. Tamir
On Sat, Oct 12, 2024 at 4:25 PM Tamir Duberstein <tamird@gmail.com> wrote: > > In order for this to be reasonably maintainable we'd want the variable > to be something like DYLIB_SUFFIX so that we don't have to revisit this > if macros are ever provided by more than one crate (or worse, have to > provide N variables). That is reasonable, and in this it is probably the right approach since the complexity is similar, but I wanted to clarify that, in the kernel, revisiting is fine and expected (features are generally not added if they are not used or expected to be used very soon, so revisiting to add a more complex feature later is the normal approach). But before we do that, is there a way to force `rustc` to load current name (or trick it to do so, say, with a symlink)? i.e. can it be reasonably done out-of-tree without changes to the filename? Thanks! Cheers, Miguel
On Sat, Oct 12, 2024 at 7:37 PM Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > But before we do that, is there a way to force `rustc` to load current > name (or trick it to do so, say, with a symlink)? i.e. can it be > reasonably done out-of-tree without changes to the filename? I think the problem is that rustc produces .dylib on macOS rather than it _looking_ for .dylib; the path to the .so is fully specified in the rustc invocation of the targets that depend on it. I don't know of a way to control the file suffix externally. A symlink would possibly work (unless rustc refuses to load anything other than .dylib on macOS for whatever reason), but wouldn't be very ergonomic; you'd have to create the symlink blind or else run the build system until it fails, then create the symlink, and then run the build again.
On Sun, Oct 13, 2024 at 1:53 AM Tamir Duberstein <tamird@gmail.com> wrote: > > A symlink would possibly work (unless rustc refuses to load anything > other than .dylib on macOS for whatever reason), but wouldn't be very > ergonomic; you'd have to create the symlink blind or else run the build > system until it fails, then create the symlink, and then run the build > again. Could you please test if the symlink work? It is definitely not elegant, and if we start having several macro crates, it will not really work for you. However, it would be good to know the potential options available here and, if it works, it would allow you to get it working right away while upstream Rust replies. Thanks! Cheers, Miguel
On Sun, Oct 13, 2024 at 8:53 AM Tamir Duberstein <tamird@gmail.com> wrote: > > On Sat, Oct 12, 2024 at 7:37 PM Miguel Ojeda > <miguel.ojeda.sandonis@gmail.com> wrote: > > But before we do that, is there a way to force `rustc` to load current > > name (or trick it to do so, say, with a symlink)? i.e. can it be > > reasonably done out-of-tree without changes to the filename? > > I think the problem is that rustc produces .dylib on macOS rather than > it _looking_ for .dylib; the path to the .so is fully specified in the > rustc invocation of the targets that depend on it. I don't know of a way > to control the file suffix externally. rustc ignores --emit=link=rust/libmacro.so and produces rust/libmacro.dylib. Is this a bug in rustc? > A symlink would possibly work (unless rustc refuses to load anything > other than .dylib on macOS for whatever reason), but wouldn't be very > ergonomic; you'd have to create the symlink blind or else run the build > system until it fails, then create the symlink, and then run the build > again. -- Best Regards Masahiro Yamada
On Mon, Oct 14, 2024 at 8:46 PM Masahiro Yamada <masahiroy@kernel.org> wrote: > > rustc ignores --emit=link=rust/libmacro.so > and produces rust/libmacro.dylib. > > Is this a bug in rustc? Hmm... From a quick test in Linux and macOS (in a GitHub runner): uname echo | rustc --crate-type=proc-macro --emit=link=a.so - echo | rustc --crate-type=proc-macro --emit=link=b.dylib - file a.so file b.dylib gives: Darwin a.so: Mach-O 64-bit dynamically linked shared library arm64 b.dylib: Mach-O 64-bit dynamically linked shared library arm64 Linux a.so: ELF 64-bit LSB shared object, x86-64, version 1... b.dylib: ELF 64-bit LSB shared object, x86-64, version 1... Cheers, Miguel
On Mon, Oct 14, 2024 at 3:09 PM Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > On Mon, Oct 14, 2024 at 8:46 PM Masahiro Yamada <masahiroy@kernel.org> wrote: > > > > rustc ignores --emit=link=rust/libmacro.so > > and produces rust/libmacro.dylib. > > > > Is this a bug in rustc? This was my bad - I set this thread down the wrong path. In fact the current build produces libmacros.so, but I haven't been able to convince rustc to consume it. Changing `--extern macros` to `--extern macros=$(objtree)/$(obj)/libmacros.so` produces 'error[E0463]: can't find crate for `macros`'. With a toy example, trying to link a proc-macro crate .so produces a more informative message than the kernel build does: ``` rustc main.rs --extern macros=./libmacros.so error: extern location for macros is of an unknown type: ./libmacros.so --> main.rs:4:1 | 4 | extern crate macros; | ^^^^^^^^^^^^^^^^^^^^ error: file name should be lib*.rlib or lib*.dylib --> main.rs:4:1 | 4 | extern crate macros; | ^^^^^^^^^^^^^^^^^^^^ ``` I've opened https://github.com/rust-lang/rust/issues/131720, let's see what the experts think.
On Tue, Oct 15, 2024 at 3:11 AM Tamir Duberstein <tamird@gmail.com> wrote: > > I've opened https://github.com/rust-lang/rust/issues/131720, let's see > what the experts think. Thanks -- I added some context there and linked to it (and Lore) in our list: https://github.com/Rust-for-Linux/linux/issues/355 Cheers, Miguel
I did more digging and I don't think this is going to be readily fixable upstream: see https://github.com/rust-lang/rust/issues/131720#issuecomment-2414179941. A symlink fixes the problem if we *never* specify a path to libmacros.so, is that how we want to proceed? Note that currently we do specify it in one place in rust/Makefile and again in generate_rust_analyzer.py, so those would need updates. Tamir
On Tue, Oct 15, 2024 at 5:06 PM Tamir Duberstein <tamird@gmail.com> wrote: > > I did more digging and I don't think this is going to be readily > fixable upstream: > see https://github.com/rust-lang/rust/issues/131720#issuecomment-2414179941. > > A symlink fixes the problem if we *never* specify a path to > libmacros.so, is that how we want to proceed? Note that currently we do > specify it in one place in rust/Makefile and again in > generate_rust_analyzer.py, so those would need updates. If a trick still requires a similar amount of changes to mainline, then I think we should go for something better/more proper, i.e. the idea is to minimize changes/complexity upstream, after all. Thanks! Cheers, Miguel
On Tue, Oct 15, 2024 at 11:30 AM Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > If a trick still requires a similar amount of changes to mainline, > then I think we should go for something better/more proper, i.e. the > idea is to minimize changes/complexity upstream, after all. In that case v5[0] is probably the way to go? On Mon, Oct 14, 2024 at 2:45 PM Masahiro Yamada <masahiroy@kernel.org> wrote: > This no-clean-files is meaningless and unnecessary. > This line exists inside the "ifdef CONFIG_RUST" ... "endif" block. > > no-clean-files is only used by scripts/Makefile.clean, > which does not include include/config/auto.conf. I see. Was it necessary before this patch? Looks like it came with the initial rust support patch. [0] https://lore.kernel.org/all/20241010142833.98528-2-tamird@gmail.com/
On Wed, Oct 16, 2024 at 12:53 AM Tamir Duberstein <tamird@gmail.com> wrote: > > On Tue, Oct 15, 2024 at 11:30 AM Miguel Ojeda > <miguel.ojeda.sandonis@gmail.com> wrote: > > > > If a trick still requires a similar amount of changes to mainline, > > then I think we should go for something better/more proper, i.e. the > > idea is to minimize changes/complexity upstream, after all. > > In that case v5[0] is probably the way to go? > > On Mon, Oct 14, 2024 at 2:45 PM Masahiro Yamada <masahiroy@kernel.org> wrote: > > This no-clean-files is meaningless and unnecessary. > > This line exists inside the "ifdef CONFIG_RUST" ... "endif" block. > > > > no-clean-files is only used by scripts/Makefile.clean, > > which does not include include/config/auto.conf. > > I see. Was it necessary before this patch? Looks like it came with the > initial rust support patch. You can just delete no-clean-files from your patch. Files specified to $(always-y) are removed by "make clean". That's why [0] added no-clean-files to negate it. You are moving "always-$(CONFIG_RUST) += libmacros.so" into the "ifdef CONFIG_RUST" ... "endif" block, which is not parsed by "make clean". > > [0] https://lore.kernel.org/all/20241010142833.98528-2-tamird@gmail.com/ -- Best Regards Masahiro Yamada
Rust proc-macro crates are loaded by the compiler at compile-time, so
are always dynamic libraries; on macOS, these artifacts get a .dylib
extension rather than .so.
Replace hardcoded paths ending in .so with paths obtained from the
compiler.
This allows the kernel to build with CONFIG_RUST=y on macOS.
Co-developed-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
V4 -> V5: Added missing `shell` in rust/Makefile.
V3 -> V4: Added motivation. Added missing Signed-off-by.
V2 -> V3: Added .strip() to rustc output to remove errant newline.
V1 -> V2: De-duplicated and sorted imports. Changed Signed-off-by to
Co-developed-by.
.gitignore | 1 +
Makefile | 2 +-
rust/Makefile | 21 ++++++++++++---------
scripts/generate_rust_analyzer.py | 15 +++++++++++----
4 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/.gitignore b/.gitignore
index a61e4778d011..088696a6a46a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
*.dtb.S
*.dtbo.S
*.dwo
+*.dylib
*.elf
*.gcno
*.gcda
diff --git a/Makefile b/Makefile
index a9e723cb0596..470e6f20c513 100644
--- a/Makefile
+++ b/Makefile
@@ -1513,7 +1513,7 @@ MRPROPER_FILES += include/config include/generated \
certs/x509.genkey \
vmlinux-gdb.py \
rpmbuild \
- rust/libmacros.so
+ rust/libmacros.so rust/libmacros.dylib
# clean - Delete most, but leave enough to build external modules
#
diff --git a/rust/Makefile b/rust/Makefile
index 0856fd6bc610..2e9fd151fce4 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -11,9 +11,6 @@ always-$(CONFIG_RUST) += exports_core_generated.h
obj-$(CONFIG_RUST) += helpers/helpers.o
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
-always-$(CONFIG_RUST) += libmacros.so
-no-clean-files += libmacros.so
-
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
always-$(CONFIG_RUST) += exports_alloc_generated.h exports_helpers_generated.h \
@@ -36,9 +33,15 @@ always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
-# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
+# Avoids running `$(RUSTC)` when it may not be available.
ifdef CONFIG_RUST
+libmacros_name := $(shell $(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - < /dev/null)
+libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name))
+
+always-$(CONFIG_RUST) += $(libmacros_name)
+no-clean-files += $(libmacros_name)
+
# `$(rust_flags)` is passed in case the user added `--sysroot`.
rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
rustc_host_target := $(shell $(RUSTC) --version --verbose | grep -F 'host: ' | cut -d' ' -f2)
@@ -118,10 +121,10 @@ rustdoc-alloc: $(RUST_LIB_SRC)/alloc/src/lib.rs rustdoc-core rustdoc-compiler_bu
+$(call if_changed,rustdoc)
rustdoc-kernel: private rustc_target_flags = --extern alloc \
- --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
+ --extern build_error --extern macros=$(objtree)/$(obj)/$(libmacros_name) \
--extern bindings --extern uapi
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
- rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
+ rustdoc-compiler_builtins rustdoc-alloc $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
+$(call if_changed,rustdoc)
@@ -342,10 +345,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
-Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro \
- --crate-name $(patsubst lib%.so,%,$(notdir $@)) $<
+ --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) $<
# Procedural macros can only be used with the `rustc` that compiled it.
-$(obj)/libmacros.so: $(src)/macros/lib.rs FORCE
+$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacro)
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
@@ -424,7 +427,7 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
--extern build_error --extern macros --extern bindings --extern uapi
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
- $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
+ $(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE
+$(call if_changed_rule,rustc_library)
endif # CONFIG_RUST
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index d2bc63cde8c6..04ff5b25b851 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -8,6 +8,7 @@ import json
import logging
import os
import pathlib
+import subprocess
import sys
def args_crates_cfgs(cfgs):
@@ -35,8 +36,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
crates_cfgs = args_crates_cfgs(cfgs)
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
- crates_indexes[display_name] = len(crates)
- crates.append({
+ crate = {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
@@ -47,7 +47,15 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
- })
+ }
+ if is_proc_macro:
+ proc_macro_dylib_name = subprocess.check_output(
+ [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
+ stdin=subprocess.DEVNULL,
+ ).decode('utf-8').strip()
+ crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
+ crates_indexes[display_name] = len(crates)
+ crates.append(crate)
# First, the ones in `rust/` since they are a bit special.
append_crate(
@@ -77,7 +85,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
[],
is_proc_macro=True,
)
- crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so"
append_crate(
"build_error",
--
2.47.0
On Thu, Oct 10, 2024 at 11:29 PM Tamir Duberstein <tamird@gmail.com> wrote: > > Rust proc-macro crates are loaded by the compiler at compile-time, so > are always dynamic libraries; on macOS, these artifacts get a .dylib > extension rather than .so. > > Replace hardcoded paths ending in .so with paths obtained from the > compiler. > > This allows the kernel to build with CONFIG_RUST=y on macOS. > > Co-developed-by: Fiona Behrens <me@kloenk.dev> > Signed-off-by: Fiona Behrens <me@kloenk.dev> > Signed-off-by: Tamir Duberstein <tamird@gmail.com> > --- > V4 -> V5: Added missing `shell` in rust/Makefile. > V3 -> V4: Added motivation. Added missing Signed-off-by. > V2 -> V3: Added .strip() to rustc output to remove errant newline. > V1 -> V2: De-duplicated and sorted imports. Changed Signed-off-by to > Co-developed-by. > > .gitignore | 1 + > Makefile | 2 +- > rust/Makefile | 21 ++++++++++++--------- > scripts/generate_rust_analyzer.py | 15 +++++++++++---- > 4 files changed, 25 insertions(+), 14 deletions(-) > > diff --git a/.gitignore b/.gitignore > index a61e4778d011..088696a6a46a 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -22,6 +22,7 @@ > *.dtb.S > *.dtbo.S > *.dwo > +*.dylib > *.elf > *.gcno > *.gcda > diff --git a/Makefile b/Makefile > index a9e723cb0596..470e6f20c513 100644 > --- a/Makefile > +++ b/Makefile > @@ -1513,7 +1513,7 @@ MRPROPER_FILES += include/config include/generated \ > certs/x509.genkey \ > vmlinux-gdb.py \ > rpmbuild \ > - rust/libmacros.so > + rust/libmacros.so rust/libmacros.dylib > > # clean - Delete most, but leave enough to build external modules > # > diff --git a/rust/Makefile b/rust/Makefile > index 0856fd6bc610..2e9fd151fce4 100644 > --- a/rust/Makefile > +++ b/rust/Makefile > @@ -11,9 +11,6 @@ always-$(CONFIG_RUST) += exports_core_generated.h > obj-$(CONFIG_RUST) += helpers/helpers.o > CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations > > -always-$(CONFIG_RUST) += libmacros.so > -no-clean-files += libmacros.so > - > always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs > obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o > always-$(CONFIG_RUST) += exports_alloc_generated.h exports_helpers_generated.h \ > @@ -36,9 +33,15 @@ always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c > obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o > obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o > > -# Avoids running `$(RUSTC)` for the sysroot when it may not be available. > +# Avoids running `$(RUSTC)` when it may not be available. > ifdef CONFIG_RUST > > +libmacros_name := $(shell $(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - < /dev/null) > +libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name)) > + > +always-$(CONFIG_RUST) += $(libmacros_name) > +no-clean-files += $(libmacros_name) This no-clean-files is meaningless and unnecessary. This line exists inside the "ifdef CONFIG_RUST" ... "endif" block. no-clean-files is only used by scripts/Makefile.clean, which does not include include/config/auto.conf. -- Best Regards Masahiro Yamada
On Wed, Oct 9, 2024 at 9:13 AM Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > On Wed, Oct 9, 2024 at 2:57 PM Tamir Duberstein <tamird@gmail.com> wrote: > > > > What would you have me link to? With this patch applied and using > > I was thinking perhaps the series from Daniel, if that is the latest > discussion (?), i.e. I would like to understand what is the policy > around changes like this, what happens if it breaks, etc. Ah, I see. The relevant discussion took place on zulip[0]. As for policy: I'm guessing there isn't one, and the whole endeavor is best-effort. Daniel's other patches weren't necessary for the kernel config I'm using. > > https://github.com/bee-headers/homebrew-bee-headers I was able to build a kernel > > on my apple silicon mac. Relevant config: > > That is great. > > Thanks! > > Cheers, > Miguel Thanks Miguel! As this is my first patch, please let me know if further action is required. Cheers. Tamir [0] https://rust-for-linux.zulipchat.com/#narrow/stream/288089-General/topic/macOS.20build
On Wed, Oct 9, 2024 at 3:18 PM Tamir Duberstein <tamird@gmail.com> wrote: > > Ah, I see. The relevant discussion took place on zulip[0]. As for policy: I'm > guessing there isn't one, and the whole endeavor is best-effort. I am aware of that discussion (it is in our Zulip), but I was referring to the kernel-wide macOS support, because I had read Daniel's summary and v2 of that series, and it is not clear to me what is the latest status on supporting macOS. In particular, there were some patches NAK'd with arguments that may apply here (e.g. extra process spawns). Moreover, how will it get tested going forward? (e.g. currently I can't, but I could look into setting something up if the kernel wants to support this). If it breaks, is it considered a bug? etc. > Thanks Miguel! As this is my first patch, please let me know if further action > is required. You're welcome! Yes, a new version would be needed with the proper tags/authorship, but first we should probably wait to hear what Kbuild (or the kernel) thinks. Cheers, Miguel
On Wed, Oct 9, 2024 at 10:20 AM Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote: > > In particular, there were some patches NAK'd with arguments that may > apply here (e.g. extra process spawns). Understood. My guess is nobody will care about the process spawn in scripts/generate_rust_analyzer.py. Someone might care about the one in rust/Makefile, but there are already 4 others. By the way, I notice those are using $(shell ...) - should I be using that form as well? > Moreover, how will it get tested going forward? (e.g. currently I > can't, but I could look into setting something up if the kernel wants > to support this). If it breaks, is it considered a bug? etc. I guess that's not for me to say. It would be great to have basic automation. > > Thanks Miguel! As this is my first patch, please let me know if further action > > is required. > > You're welcome! Yes, a new version would be needed with the proper > tags/authorship, but first we should probably wait to hear what Kbuild > (or the kernel) thinks. > > Cheers, > Miguel > Please read the section of the documentation I linked, it contains an > example on how this should be done, i.e. the Co-developed-by tag > cannot be on its own: My apologies for the oversight.
On Wed, Oct 9, 2024 at 4:48 PM Tamir Duberstein <tamird@gmail.com> wrote: > > Understood. My guess is nobody will care about the process spawn in > scripts/generate_rust_analyzer.py. Someone might care about the one in > rust/Makefile, but there are already 4 others. By the way, I notice those are Yeah, I was referring to the `Makefile` one (the other one, indeed, does not matter, as you say). > using $(shell ...) - should I be using that form as well? Hmm... I assume you tested the patch, but how would the patch work without it? Or am I confused? > I guess that's not for me to say. It would be great to have basic automation. Generally, when submitting a new feature for upstream, especially one that requires new testing, it is common that the submitter is asked to take care of it or help doing so. I guess, in this case, Daniel is the one handling the macOS support out-of-tree. Anyway, we may need to use variables for this, so I think it is fine -- upstream can keep the variable working easily, and out-of-tree can test the overall macOS support. > My apologies for the oversight. No worries, thanks! Cheers, Miguel
Rust proc-macro crates are loaded by the compiler at compile-time, so
are always dynamic libraries; on macOS, these artifacts get a .dylib
extension rather than .so.
Replace hardcoded paths ending in .so with paths obtained from the
compiler.
Co-developed-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
V2 -> V3: Added .strip() to rustc output to remove errant newline.
V1 -> V2: De-duplicated and sorted imports. Changed Signed-off-by to
Co-developed-by.
.gitignore | 1 +
Makefile | 2 +-
rust/Makefile | 21 ++++++++++++---------
scripts/generate_rust_analyzer.py | 15 +++++++++++----
4 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/.gitignore b/.gitignore
index a61e4778d011..088696a6a46a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
*.dtb.S
*.dtbo.S
*.dwo
+*.dylib
*.elf
*.gcno
*.gcda
diff --git a/Makefile b/Makefile
index a9e723cb0596..470e6f20c513 100644
--- a/Makefile
+++ b/Makefile
@@ -1513,7 +1513,7 @@ MRPROPER_FILES += include/config include/generated \
certs/x509.genkey \
vmlinux-gdb.py \
rpmbuild \
- rust/libmacros.so
+ rust/libmacros.so rust/libmacros.dylib
# clean - Delete most, but leave enough to build external modules
#
diff --git a/rust/Makefile b/rust/Makefile
index 0856fd6bc610..94ae550ae8b3 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -11,9 +11,6 @@ always-$(CONFIG_RUST) += exports_core_generated.h
obj-$(CONFIG_RUST) += helpers/helpers.o
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
-always-$(CONFIG_RUST) += libmacros.so
-no-clean-files += libmacros.so
-
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
always-$(CONFIG_RUST) += exports_alloc_generated.h exports_helpers_generated.h \
@@ -36,9 +33,15 @@ always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
-# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
+# Avoids running `$(RUSTC)` when it may not be available.
ifdef CONFIG_RUST
+libmacros_name := $($(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - < /dev/null)
+libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name))
+
+always-$(CONFIG_RUST) += $(libmacros_name)
+no-clean-files += $(libmacros_name)
+
# `$(rust_flags)` is passed in case the user added `--sysroot`.
rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
rustc_host_target := $(shell $(RUSTC) --version --verbose | grep -F 'host: ' | cut -d' ' -f2)
@@ -118,10 +121,10 @@ rustdoc-alloc: $(RUST_LIB_SRC)/alloc/src/lib.rs rustdoc-core rustdoc-compiler_bu
+$(call if_changed,rustdoc)
rustdoc-kernel: private rustc_target_flags = --extern alloc \
- --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
+ --extern build_error --extern macros=$(objtree)/$(obj)/$(libmacros_name) \
--extern bindings --extern uapi
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
- rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
+ rustdoc-compiler_builtins rustdoc-alloc $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
+$(call if_changed,rustdoc)
@@ -342,10 +345,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
-Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro \
- --crate-name $(patsubst lib%.so,%,$(notdir $@)) $<
+ --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) $<
# Procedural macros can only be used with the `rustc` that compiled it.
-$(obj)/libmacros.so: $(src)/macros/lib.rs FORCE
+$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacro)
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
@@ -424,7 +427,7 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
--extern build_error --extern macros --extern bindings --extern uapi
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
- $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
+ $(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE
+$(call if_changed_rule,rustc_library)
endif # CONFIG_RUST
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index d2bc63cde8c6..04ff5b25b851 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -8,6 +8,7 @@ import json
import logging
import os
import pathlib
+import subprocess
import sys
def args_crates_cfgs(cfgs):
@@ -35,8 +36,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
crates_cfgs = args_crates_cfgs(cfgs)
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
- crates_indexes[display_name] = len(crates)
- crates.append({
+ crate = {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
@@ -47,7 +47,15 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
- })
+ }
+ if is_proc_macro:
+ proc_macro_dylib_name = subprocess.check_output(
+ [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
+ stdin=subprocess.DEVNULL,
+ ).decode('utf-8').strip()
+ crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
+ crates_indexes[display_name] = len(crates)
+ crates.append(crate)
# First, the ones in `rust/` since they are a bit special.
append_crate(
@@ -77,7 +85,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
[],
is_proc_macro=True,
)
- crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so"
append_crate(
"build_error",
--
2.47.0
On Wed, Oct 9, 2024 at 4:16 PM Tamir Duberstein <tamird@gmail.com> wrote: > > Rust proc-macro crates are loaded by the compiler at compile-time, so > are always dynamic libraries; on macOS, these artifacts get a .dylib > extension rather than .so. > > Replace hardcoded paths ending in .so with paths obtained from the > compiler. Nit: this should mention what the overall purpose of the patch is, i.e. "why we are doing this?", i.e. supporting macOS builds. It is maybe obvious since macOS is mentioned (in the "what does this patch do?" part), but it is best to be explicit. > Co-developed-by: Fiona Behrens <me@kloenk.dev> > Signed-off-by: Tamir Duberstein <tamird@gmail.com> Please read the section of the documentation I linked, it contains an example on how this should be done, i.e. the Co-developed-by tag cannot be on its own: https://docs.kernel.org/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by `scripts/checkpatch.pl` also warns about this -- please run patches through it: WARNING: Co-developed-by and Signed-off-by: name/email do not match Cheers, Miguel
Rust proc-macro crates are loaded by the compiler at compile-time, so
are always dynamic libraries; on macOS, these artifacts get a .dylib
extension rather than .so.
Replace hardcoded paths ending in .so with paths obtained from the
compiler.
This allows the kernel to build with CONFIG_RUST=y on macOS.
Co-developed-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Fiona Behrens <me@kloenk.dev>
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
V3 -> V4: Added motivation. Added missing Signed-off-by.
V2 -> V3: Added .strip() to rustc output to remove errant newline.
V1 -> V2: De-duplicated and sorted imports. Changed Signed-off-by to
Co-developed-by.
.gitignore | 1 +
Makefile | 2 +-
rust/Makefile | 21 ++++++++++++---------
scripts/generate_rust_analyzer.py | 15 +++++++++++----
4 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/.gitignore b/.gitignore
index a61e4778d011..088696a6a46a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
*.dtb.S
*.dtbo.S
*.dwo
+*.dylib
*.elf
*.gcno
*.gcda
diff --git a/Makefile b/Makefile
index a9e723cb0596..470e6f20c513 100644
--- a/Makefile
+++ b/Makefile
@@ -1513,7 +1513,7 @@ MRPROPER_FILES += include/config include/generated \
certs/x509.genkey \
vmlinux-gdb.py \
rpmbuild \
- rust/libmacros.so
+ rust/libmacros.so rust/libmacros.dylib
# clean - Delete most, but leave enough to build external modules
#
diff --git a/rust/Makefile b/rust/Makefile
index 0856fd6bc610..94ae550ae8b3 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -11,9 +11,6 @@ always-$(CONFIG_RUST) += exports_core_generated.h
obj-$(CONFIG_RUST) += helpers/helpers.o
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
-always-$(CONFIG_RUST) += libmacros.so
-no-clean-files += libmacros.so
-
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
always-$(CONFIG_RUST) += exports_alloc_generated.h exports_helpers_generated.h \
@@ -36,9 +33,15 @@ always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
-# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
+# Avoids running `$(RUSTC)` when it may not be available.
ifdef CONFIG_RUST
+libmacros_name := $($(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - < /dev/null)
+libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name))
+
+always-$(CONFIG_RUST) += $(libmacros_name)
+no-clean-files += $(libmacros_name)
+
# `$(rust_flags)` is passed in case the user added `--sysroot`.
rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
rustc_host_target := $(shell $(RUSTC) --version --verbose | grep -F 'host: ' | cut -d' ' -f2)
@@ -118,10 +121,10 @@ rustdoc-alloc: $(RUST_LIB_SRC)/alloc/src/lib.rs rustdoc-core rustdoc-compiler_bu
+$(call if_changed,rustdoc)
rustdoc-kernel: private rustc_target_flags = --extern alloc \
- --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
+ --extern build_error --extern macros=$(objtree)/$(obj)/$(libmacros_name) \
--extern bindings --extern uapi
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
- rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
+ rustdoc-compiler_builtins rustdoc-alloc $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
+$(call if_changed,rustdoc)
@@ -342,10 +345,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
-Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro \
- --crate-name $(patsubst lib%.so,%,$(notdir $@)) $<
+ --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) $<
# Procedural macros can only be used with the `rustc` that compiled it.
-$(obj)/libmacros.so: $(src)/macros/lib.rs FORCE
+$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacro)
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
@@ -424,7 +427,7 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
$(obj)/kernel.o: private rustc_target_flags = --extern alloc \
--extern build_error --extern macros --extern bindings --extern uapi
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
- $(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
+ $(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE
+$(call if_changed_rule,rustc_library)
endif # CONFIG_RUST
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index d2bc63cde8c6..04ff5b25b851 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -8,6 +8,7 @@ import json
import logging
import os
import pathlib
+import subprocess
import sys
def args_crates_cfgs(cfgs):
@@ -35,8 +36,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
crates_cfgs = args_crates_cfgs(cfgs)
def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
- crates_indexes[display_name] = len(crates)
- crates.append({
+ crate = {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
@@ -47,7 +47,15 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
- })
+ }
+ if is_proc_macro:
+ proc_macro_dylib_name = subprocess.check_output(
+ [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
+ stdin=subprocess.DEVNULL,
+ ).decode('utf-8').strip()
+ crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
+ crates_indexes[display_name] = len(crates)
+ crates.append(crate)
# First, the ones in `rust/` since they are a bit special.
append_crate(
@@ -77,7 +85,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs):
[],
is_proc_macro=True,
)
- crates[-1]["proc_macro_dylib_path"] = f"{objtree}/rust/libmacros.so"
append_crate(
"build_error",
--
2.47.0
© 2016 - 2024 Red Hat, Inc.