7070_OWNING_KINDS = frozenset ("TtBbDdGgSsRrWV" )
7171
7272_CONSUMER_SOURCE = """\
73+ #include <executorch/extension/module/module.h>
74+ #include <executorch/extension/tensor/tensor.h>
7375#include <executorch/runtime/backend/interface.h>
7476#include <executorch/runtime/platform/runtime.h>
7577
7678#include <cstdio>
79+ #include <vector>
80+
81+ using namespace executorch::extension;
7782
7883int main() {
7984 executorch::runtime::runtime_init();
8085 std::printf(
8186 "registered backends: %zu\\ n",
8287 (size_t)executorch::runtime::get_num_registered_backends());
88+
89+ // The documented entry points, not just the lower-level runtime. Constructing these
90+ // needs real definitions at link time, so it checks that the shipped headers and the
91+ // shipped library agree rather than only that the headers parse.
92+ module::Module module("nonexistent.pte");
93+ std::vector<float> data(4, 1.0f);
94+ auto input = make_tensor_ptr({2, 2}, data.data());
95+ std::printf("tensor holds %zu values\\ n", (size_t)input->numel());
96+
97+ // A missing file is the expected outcome here. What matters is that the call resolves
98+ // and returns an error rather than failing to link.
99+ const auto error = module.load();
100+ std::printf("module load returned 0x%x as expected\\ n", (unsigned)error);
83101 return 0;
84102}
85103"""
@@ -793,6 +811,62 @@ def test_component_targets_link(work_dir: Path) -> None:
793811 print (f"✓ every offered component links and is retained: { sorted (linked )} " )
794812
795813
814+ def test_documented_example_compiles (work_dir : Path ) -> None :
815+ """The C++ example in the documentation must compile against the installed wheel.
816+
817+ Extracted from the documentation rather than copied here, so the two cannot drift. A
818+ reader who follows the documentation gets code that builds, and a dangling include or a
819+ renamed entry point fails this check instead of shipping.
820+ """
821+ # Guarded the same way the wheel lookup is: a copy of this file can live outside the
822+ # repository layout, where indexing past the available parents raises.
823+ here = Path (__file__ ).resolve ()
824+ root = here .parents [3 ] if len (here .parents ) > 3 else here .parent
825+ documentation = root / "docs" / "source" / "using-executorch-cpp.md"
826+ if not documentation .is_file ():
827+ print ("- the documentation file is not present, skipping the example check" )
828+ return
829+
830+ match = re .search (
831+ r"```cpp\n// main\.cpp\n(.*?)```" , documentation .read_text (), re .S
832+ )
833+ assert match , (
834+ f"could not find the C++ example in { documentation .name } ; the check needs it to "
835+ "verify what the documentation tells a reader to write"
836+ )
837+
838+ source_dir = work_dir / "documented"
839+ source_dir .mkdir (parents = True , exist_ok = True )
840+ (source_dir / "main.cpp" ).write_text ("// main.cpp\n " + match .group (1 ))
841+ (source_dir / "CMakeLists.txt" ).write_text (
842+ "cmake_minimum_required(VERSION 3.28)\n "
843+ "project(documented_example CXX)\n "
844+ "find_package(executorch REQUIRED)\n "
845+ "add_executable(documented_example main.cpp)\n "
846+ "target_link_libraries(documented_example PRIVATE executorch::runtime)\n "
847+ )
848+
849+ build_dir = work_dir / "documented-build"
850+ configure = subprocess .run (
851+ ["cmake" , "-S" , str (source_dir ), "-B" , str (build_dir ),
852+ f"-DCMAKE_PREFIX_PATH={ _installed_package_dir ()} " ],
853+ capture_output = True , text = True , check = False ,
854+ )
855+ assert configure .returncode == 0 , (
856+ "the documented example does not configure against the installed wheel: "
857+ f"{ (configure .stderr or configure .stdout ).strip ()[- 500 :]} "
858+ )
859+ build = subprocess .run (
860+ ["cmake" , "--build" , str (build_dir )],
861+ capture_output = True , text = True , check = False ,
862+ )
863+ assert build .returncode == 0 , (
864+ "the documented example does not compile against the installed wheel: "
865+ f"{ (build .stderr or build .stdout ).strip ()[- 500 :]} "
866+ )
867+ print ("\u2713 the C++ example in the documentation compiles and links" )
868+
869+
796870def run_tests (work_dir : Path ) -> None :
797871 test_single_backend_registry ()
798872 test_python_extensions_import ()
@@ -805,4 +879,5 @@ def run_tests(work_dir: Path) -> None:
805879 test_single_kernel_registration ()
806880 test_single_xnnpack_delegate ()
807881 test_cpp_consumer (work_dir )
882+ test_documented_example_compiles (work_dir )
808883 test_component_targets_link (work_dir )
0 commit comments