Factor out genrules to rust_cxx_bridge.bzl
diff --git a/demo/BUCK b/demo/BUCK
index 7b476a5..846c149 100644
--- a/demo/BUCK
+++ b/demo/BUCK
@@ -1,4 +1,4 @@
-load("//tools/buck:genrule.bzl", "genrule")
+load("//tools/buck:rust_cxx_bridge.bzl", "rust_cxx_bridge")
 
 rust_binary(
     name = "demo",
@@ -10,34 +10,10 @@
     ],
 )
 
-cxx_library(
+rust_cxx_bridge(
     name = "bridge",
-    srcs = [":bridge/source"],
-    deps = [
-        ":bridge/include",
-        ":demo-include",
-    ],
-)
-
-genrule(
-    name = "bridge/header",
-    srcs = ["src/main.rs"],
-    out = "src/main.rs.h",
-    cmd = "$(exe //:codegen) --header ${SRCS} > ${OUT}",
-    type = "cxxbridge",
-)
-
-genrule(
-    name = "bridge/source",
-    srcs = ["src/main.rs"],
-    out = "src/main.rs.cc",
-    cmd = "$(exe //:codegen) ${SRCS} > ${OUT}",
-    type = "cxxbridge",
-)
-
-cxx_library(
-    name = "bridge/include",
-    exported_headers = [":bridge/header"],
+    src = "src/main.rs",
+    deps = [":demo-include"],
 )
 
 cxx_library(
diff --git a/demo/BUILD b/demo/BUILD
index 6e07e5e..5bc8c77 100644
--- a/demo/BUILD
+++ b/demo/BUILD
@@ -1,5 +1,6 @@
 load("@rules_cc//cc:defs.bzl", "cc_library")
 load("//tools/bazel:rust.bzl", "rust_binary")
+load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
 
 rust_binary(
     name = "demo",
@@ -11,34 +12,10 @@
     ],
 )
 
-cc_library(
+rust_cxx_bridge(
     name = "bridge",
-    srcs = [":bridge/source"],
-    deps = [
-        ":bridge/include",
-        ":demo-include",
-    ],
-)
-
-genrule(
-    name = "bridge/header",
-    srcs = ["src/main.rs"],
-    outs = ["src/main.rs.h"],
-    cmd = "$(location //:codegen) --header $< > $@",
-    tools = ["//:codegen"],
-)
-
-genrule(
-    name = "bridge/source",
-    srcs = ["src/main.rs"],
-    outs = ["src/main.rs.cc"],
-    cmd = "$(location //:codegen) $< > $@",
-    tools = ["//:codegen"],
-)
-
-cc_library(
-    name = "bridge/include",
-    hdrs = [":bridge/header"],
+    src = "src/main.rs",
+    deps = [":demo-include"],
 )
 
 cc_library(
diff --git a/tests/BUCK b/tests/BUCK
index a5bd044..47fc557 100644
--- a/tests/BUCK
+++ b/tests/BUCK
@@ -1,4 +1,4 @@
-load("//tools/buck:genrule.bzl", "genrule")
+load("//tools/buck:rust_cxx_bridge.bzl", "rust_cxx_bridge")
 
 rust_test(
     name = "test",
@@ -34,23 +34,12 @@
     deps = ["//:core"],
 )
 
-genrule(
-    name = "bridge/header",
-    srcs = ["ffi/lib.rs"],
-    out = "ffi/lib.rs.h",
-    cmd = "$(exe //:codegen) --header ${SRCS} > ${OUT}",
+rust_cxx_bridge(
+    name = "bridge",
+    src = "ffi/lib.rs",
 )
 
-genrule(
-    name = "bridge/source",
-    srcs = ["ffi/lib.rs"],
-    out = "ffi/lib.rs.cc",
-    cmd = "$(exe //:codegen) ${SRCS} > ${OUT}",
-)
-
-genrule(
-    name = "module/source",
-    srcs = ["ffi/module.rs"],
-    out = "ffi/module.rs.cc",
-    cmd = "$(exe //:codegen) ${SRCS} > ${OUT}",
+rust_cxx_bridge(
+    name = "module",
+    src = "ffi/module.rs",
 )
diff --git a/tests/BUILD b/tests/BUILD
index 586affc..68e7be3 100644
--- a/tests/BUILD
+++ b/tests/BUILD
@@ -1,5 +1,6 @@
 load("@rules_cc//cc:defs.bzl", "cc_library")
 load("//tools/bazel:rust.bzl", "rust_library", "rust_test")
+load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge")
 
 rust_test(
     name = "test",
@@ -36,33 +37,18 @@
     ],
 )
 
-genrule(
-    name = "bridge/header",
-    srcs = ["ffi/lib.rs"],
-    outs = ["ffi/lib.rs.h"],
-    cmd = "$(location //:codegen) --header $< > $@",
-    tools = ["//:codegen"],
-)
-
-genrule(
-    name = "bridge/source",
-    srcs = ["ffi/lib.rs"],
-    outs = ["ffi/lib.rs.cc"],
-    cmd = "$(location //:codegen) $< > $@",
-    tools = ["//:codegen"],
-)
-
-cc_library(
-    name = "bridge/include",
-    hdrs = [":bridge/header"],
+rust_cxx_bridge(
+    name = "bridge",
+    src = "ffi/lib.rs",
     include_prefix = "cxx-test-suite",
     strip_include_prefix = "ffi",
+    deps = [":impl"],
 )
 
-genrule(
-    name = "module/source",
-    srcs = ["ffi/module.rs"],
-    outs = ["ffi/module.rs.cc"],
-    cmd = "$(location //:codegen) $< > $@",
-    tools = ["//:codegen"],
+rust_cxx_bridge(
+    name = "module",
+    src = "ffi/module.rs",
+    include_prefix = "cxx-test-suite",
+    strip_include_prefix = "ffi",
+    deps = [":impl"],
 )
diff --git a/tools/bazel/rust_cxx_bridge.bzl b/tools/bazel/rust_cxx_bridge.bzl
new file mode 100644
index 0000000..7f3f958
--- /dev/null
+++ b/tools/bazel/rust_cxx_bridge.bzl
@@ -0,0 +1,36 @@
+load("@rules_cc//cc:defs.bzl", "cc_library")
+
+def rust_cxx_bridge(
+        name,
+        src,
+        include_prefix = None,
+        strip_include_prefix = None,
+        deps = []):
+    native.genrule(
+        name = "%s/header" % name,
+        srcs = [src],
+        outs = [src + ".h"],
+        cmd = "$(location //:codegen) --header $< > $@",
+        tools = ["//:codegen"],
+    )
+
+    native.genrule(
+        name = "%s/source" % name,
+        srcs = [src],
+        outs = [src + ".cc"],
+        cmd = "$(location //:codegen) $< > $@",
+        tools = ["//:codegen"],
+    )
+
+    cc_library(
+        name = name,
+        srcs = [":%s/source" % name],
+        deps = deps + [":%s/include" % name],
+    )
+
+    cc_library(
+        name = "%s/include" % name,
+        hdrs = [":%s/header" % name],
+        include_prefix = include_prefix,
+        strip_include_prefix = strip_include_prefix,
+    )
diff --git a/tools/buck/rust_cxx_bridge.bzl b/tools/buck/rust_cxx_bridge.bzl
new file mode 100644
index 0000000..5fa530b
--- /dev/null
+++ b/tools/buck/rust_cxx_bridge.bzl
@@ -0,0 +1,30 @@
+load("//tools/buck:genrule.bzl", "genrule")
+
+def rust_cxx_bridge(name, src, deps = []):
+    genrule(
+        name = "%s/header" % name,
+        srcs = [src],
+        out = src + ".h",
+        cmd = "$(exe //:codegen) --header ${SRCS} > ${OUT}",
+        type = "cxxbridge",
+    )
+
+    genrule(
+        name = "%s/source" % name,
+        srcs = [src],
+        out = src + ".cc",
+        cmd = "$(exe //:codegen) ${SRCS} > ${OUT}",
+        type = "cxxbridge",
+    )
+
+    cxx_library(
+        name = name,
+        srcs = [":%s/source" % name],
+        preferred_linkage = "static",
+        deps = deps + [":%s/include" % name],
+    )
+
+    cxx_library(
+        name = "%s/include" % name,
+        exported_headers = [":%s/header" % name],
+    )