From 1bc58291898748e2883e75ca7c4a439771a73a7e Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Wed, 26 May 2021 22:29:09 +0100
Subject: [PATCH] rust: depend on `syn`

add `syn` and others as dependencies of `macros` crate, and use cargo
to build `macros` crate. Only host-facing `libmacros.so` is built this
way, not any of the other crates that are compiled for the target. This
cargo invocation has all crate versions locked and has `--offline`
option specified, so it won't access Internet during the build.

The current `module!` crate already shows it tedious and limited for
writing proc macros without `syn`. Pinning and vtable handling could
likely be drastically improved with the help of proc macros, and they
will require parsing Rust struct/trait/impl blocks. A dependency on
`syn` is highly desirable to avoid us essentially reinventing the wheel
when building our procedural macros.

A `make rust-fetch-deps` command is added and listed in the
documentation as a build requirement.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 .github/workflows/ci.yaml          |  4 +++
 Documentation/rust/quick-start.rst | 12 ++++++++
 Makefile                           |  7 ++++-
 rust/.gitignore                    |  3 +-
 rust/Makefile                      | 30 +++++++++----------
 rust/macros/Cargo.lock             | 47 ++++++++++++++++++++++++++++++
 rust/macros/Cargo.toml             | 14 +++++++++
 7 files changed, 100 insertions(+), 17 deletions(-)
 create mode 100644 rust/macros/Cargo.lock
 create mode 100644 rust/macros/Cargo.toml

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index ffe91c6beb7417..f285fce0e68014 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -205,6 +205,10 @@ jobs:
       - run: |
           curl -o bin/bindgen https://raw.githubusercontent.com/Rust-for-Linux/ci-bin/master/bindgen-0.56.0/bin/bindgen
           chmod u+x bin/bindgen
+
+      # Setup: Procedural macro dependencies
+      - run: |
+          make rust-fetch-deps
       
       # Setup: ccache
       - run: |
diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst
index 43965f8535ee8c..326267e7cd01cb 100644
--- a/Documentation/rust/quick-start.rst
+++ b/Documentation/rust/quick-start.rst
@@ -89,6 +89,18 @@ Install it via (this will build the tool from source)::
     cargo install --locked --version 0.56.0 bindgen
 
 
+Procedural macro dependencies
+*****************************
+
+We use procedural macros that need to parse Rust code. We depends on a few
+well-established crate in Rust community (`syn`, `quote` and `proc-macro2`)
+for this task.
+
+Fetch it via::
+
+    make rust-fetch-deps
+
+
 Requirements: Developing
 ------------------------
 
diff --git a/Makefile b/Makefile
index 2c4bac4898e0a8..b95512bdc1e661 100644
--- a/Makefile
+++ b/Makefile
@@ -270,7 +270,7 @@ no-dot-config-targets := $(clean-targets) \
 			 cscope gtags TAGS tags help% %docs check% coccicheck \
 			 $(version_h) headers headers_% archheaders archscripts \
 			 %asm-generic kernelversion %src-pkg dt_binding_check \
-			 outputmakefile rustfmt rustfmtcheck
+			 outputmakefile rustfmt rustfmtcheck rust-fetch-deps
 no-sync-config-targets := $(no-dot-config-targets) %install kernelrelease \
 			  image_name
 single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.s %.symtypes %/
@@ -1832,6 +1832,11 @@ rustfmt:
 rustfmtcheck:
 	find $(srctree) -type f -name '*.rs' | xargs $(RUSTFMT) --check
 
+# Procedural macros dependency fetch
+PHONY += rust-fetch-deps
+rust-fetch-deps:
+	$(Q)$(MAKE) $(build)=rust $@
+
 # IDE support targets
 PHONY += rust-analyzer
 rust-analyzer: prepare0
diff --git a/rust/.gitignore b/rust/.gitignore
index 8875e08ed0b17e..0cc32e0350e7a5 100644
--- a/rust/.gitignore
+++ b/rust/.gitignore
@@ -2,4 +2,5 @@
 
 bindings_generated.rs
 exports_*_generated.h
-doc/
\ No newline at end of file
+doc/
+target/
diff --git a/rust/Makefile b/rust/Makefile
index 9e94e687007217..52120641cd0ddd 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -35,12 +35,7 @@ quiet_cmd_rustdoc = RUSTDOC $<
 		--output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \
 		-Fmissing-docs @$(objtree)/include/generated/rustc_cfg $<
 
-rustdoc: rustdoc-macros rustdoc-compiler_builtins rustdoc-kernel
-
-rustdoc-macros: private rustdoc_target_flags = --crate-type proc-macro \
-    --extern proc_macro
-rustdoc-macros: $(srctree)/rust/macros/lib.rs FORCE
-	$(call if_changed,rustdoc_host)
+rustdoc: rustdoc-compiler_builtins rustdoc-kernel
 
 rustdoc-compiler_builtins: $(srctree)/rust/compiler_builtins.rs FORCE
 	$(call if_changed,rustdoc)
@@ -48,7 +43,7 @@ rustdoc-compiler_builtins: $(srctree)/rust/compiler_builtins.rs FORCE
 rustdoc-kernel: private rustdoc_target_flags = --extern alloc \
     --extern build_error \
     --extern macros=$(objtree)/rust/libmacros.so
-rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-macros \
+rustdoc-kernel: $(srctree)/rust/kernel/lib.rs \
     $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE
 	$(call if_changed,rustdoc)
 
@@ -113,22 +108,27 @@ $(objtree)/rust/exports_alloc_generated.h: $(objtree)/rust/alloc.o FORCE
 $(objtree)/rust/exports_kernel_generated.h: $(objtree)/rust/kernel.o FORCE
 	$(call if_changed,exports)
 
+CARGO = cargo
+
 # `-Cpanic=unwind -Cforce-unwind-tables=y` overrides `rustc_flags` in order to
 # avoid the https://github.com/rust-lang/rust/issues/82320 rustc crash.
-quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
+quiet_cmd_rustc_procmacro = CARGO P $@
       cmd_rustc_procmacro = \
-	$(RUSTC_OR_CLIPPY) $(rustc_flags) \
-		--emit=dep-info,link --extern proc_macro \
-		-Cpanic=unwind -Cforce-unwind-tables=y \
-		--crate-type proc-macro --out-dir $(objtree)/rust/ \
-		--crate-name $(patsubst lib%.so,%,$(notdir $@)) $<; \
-	mv $(objtree)/rust/$(patsubst lib%.so,%,$(notdir $@)).d $(depfile); \
+	$(CARGO) build --locked --offline --release \
+		--manifest-path $< \
+		--target-dir $(objtree)/rust/target; \
+	cp $(objtree)/rust/target/release/$(notdir $@) $@; \
+	mv $(objtree)/rust/target/release/$(patsubst %.so,%,$(notdir $@)).d $(depfile); \
+	sed -i 's/build.rs//' $(depfile); \
 	sed -i '/^\#/d' $(depfile)
 
+rust-fetch-deps:
+	$(CARGO) fetch --locked --manifest-path $(srctree)/rust/macros/Cargo.toml
+
 # Procedural macros can only be used with the `rustc` that compiled it.
 # Therefore, to get `libmacros.so` automatically recompiled when the compiler
 # version changes, we add `core.o` as a dependency (even if it is not needed).
-$(objtree)/rust/libmacros.so: $(srctree)/rust/macros/lib.rs \
+$(objtree)/rust/libmacros.so: $(srctree)/rust/macros/Cargo.toml \
 	$(objtree)/rust/core.o FORCE
 	$(call if_changed_dep,rustc_procmacro)
 
diff --git a/rust/macros/Cargo.lock b/rust/macros/Cargo.lock
new file mode 100644
index 00000000000000..bf7d701398dd21
--- /dev/null
+++ b/rust/macros/Cargo.lock
@@ -0,0 +1,47 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "macros"
+version = "0.0.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
diff --git a/rust/macros/Cargo.toml b/rust/macros/Cargo.toml
new file mode 100644
index 00000000000000..de6efaa04ce1bb
--- /dev/null
+++ b/rust/macros/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "macros"
+version = "0.0.0"
+edition = "2018"
+license = "GPL-2.0-only"
+
+[lib]
+path = "lib.rs"
+proc_macro = true
+
+[dependencies]
+syn = { version = "1.0", features = ["full"] }
+quote = "1.0"
+proc-macro2 = "1.0"