From 40eb26e580144efc9f7654bc1ba37117456360ab Mon Sep 17 00:00:00 2001 From: Scorg <8122341+Scorg@users.noreply.github.com> Date: Sat, 11 Jan 2025 13:05:31 +0500 Subject: [PATCH] build(bindings): move header to tree_sitter subdirectory This patch allows users to include the parser by the same path from local build as well as installed location. Previously it was not possible to include the header prior to installing the built parser. --- cli/src/init.rs | 78 ++++++++++++++++++++++++------ cli/src/templates/cmakelists.cmake | 10 ++-- cli/src/templates/gitattributes | 2 +- cli/src/templates/makefile | 2 +- docs/src/cli/init.md | 2 +- 5 files changed, 72 insertions(+), 22 deletions(-) diff --git a/cli/src/init.rs b/cli/src/init.rs index 73a355ce..8f1d0f2d 100644 --- a/cli/src/init.rs +++ b/cli/src/init.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::{anyhow, Context, Result}; use heck::{ToKebabCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; -use indoc::indoc; +use indoc::{formatdoc, indoc}; use semver::Version; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; @@ -288,9 +288,16 @@ pub fn generate_grammar_files( })?; // Write .gitattributes file - missing_path(repo_path.join(".gitattributes"), |path| { - generate_file(path, GITATTRIBUTES_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + repo_path.join(".gitattributes"), + allow_update, + |path| generate_file(path, GITATTRIBUTES_TEMPLATE, language_name, &generate_opts), + |path| { + let contents = fs::read_to_string(path)?; + write_file(path, contents.replace("bindings/c/* ", "bindings/c/** "))?; + Ok(()) + }, + )?; // Write .editorconfig file missing_path(repo_path.join(".editorconfig"), |path| { @@ -376,10 +383,19 @@ pub fn generate_grammar_files( // Generate C bindings if tree_sitter_config.bindings.c { missing_path(bindings_dir.join("c"), create_dir)?.apply(|path| { - missing_path( - path.join(format!("tree-sitter-{language_name}.h")), - |path| generate_file(path, PARSER_NAME_H_TEMPLATE, language_name, &generate_opts), - )?; + let old_file = &path.join(format!("tree-sitter-{language_name}.h")); + if allow_update && fs::exists(old_file).unwrap_or(false) { + fs::remove_file(old_file)?; + } + missing_path(path.join("tree_sitter"), create_dir)?.apply(|include_path| { + missing_path( + include_path.join(format!("tree-sitter-{language_name}.h")), + |path| { + generate_file(path, PARSER_NAME_H_TEMPLATE, language_name, &generate_opts) + }, + )?; + Ok(()) + })?; missing_path( path.join(format!("tree-sitter-{language_name}.pc.in")), @@ -393,20 +409,50 @@ pub fn generate_grammar_files( }, )?; - missing_path(repo_path.join("Makefile"), |path| { - generate_file(path, MAKEFILE_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + repo_path.join("Makefile"), + allow_update, + |path| { + generate_file(path, MAKEFILE_TEMPLATE, language_name, &generate_opts) + }, + |path| { + let contents = fs::read_to_string(path)?.replace( + "-m644 bindings/c/$(LANGUAGE_NAME).h", + "-m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h" + ); + write_file(path, contents)?; + Ok(()) + }, + )?; missing_path_else( repo_path.join("CMakeLists.txt"), allow_update, |path| generate_file(path, CMAKELISTS_TXT_TEMPLATE, language_name, &generate_opts), |path| { - let contents = fs::read_to_string(path)?; - let old = "add_custom_target(test"; - if contents.contains(old) { - write_file(path, contents.replace(old, "add_custom_target(ts-test"))?; - } + let mut contents = fs::read_to_string(path)?; + contents = contents + .replace("add_custom_target(test", "add_custom_target(ts-test") + .replace( + &formatdoc! {r#" + install(FILES bindings/c/tree-sitter-{language_name}.h + DESTINATION "${{CMAKE_INSTALL_INCLUDEDIR}}/tree_sitter") + "#}, + indoc! {r#" + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.h") + "#} + ).replace( + &format!("target_include_directories(tree-sitter-{language_name} PRIVATE src)"), + &formatdoc! {" + target_include_directories(tree-sitter-{language_name} + PRIVATE src + INTERFACE $ + $) + "} + ); + write_file(path, contents)?; Ok(()) }, )?; diff --git a/cli/src/templates/cmakelists.cmake b/cli/src/templates/cmakelists.cmake index 0d53ce5a..e8ba9a6c 100644 --- a/cli/src/templates/cmakelists.cmake +++ b/cli/src/templates/cmakelists.cmake @@ -28,7 +28,10 @@ add_library(tree-sitter-PARSER_NAME src/parser.c) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) target_sources(tree-sitter-PARSER_NAME PRIVATE src/scanner.c) endif() -target_include_directories(tree-sitter-PARSER_NAME PRIVATE src) +target_include_directories(tree-sitter-PARSER_NAME + PRIVATE src + INTERFACE $ + $) target_compile_definitions(tree-sitter-PARSER_NAME PRIVATE $<$:TREE_SITTER_REUSE_ALLOCATOR> @@ -46,8 +49,9 @@ configure_file(bindings/c/tree-sitter-PARSER_NAME.pc.in include(GNUInstallDirs) -install(FILES bindings/c/tree-sitter-PARSER_NAME.h - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tree_sitter") +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.h") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-PARSER_NAME.pc" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig") install(TARGETS tree-sitter-PARSER_NAME diff --git a/cli/src/templates/gitattributes b/cli/src/templates/gitattributes index 7e2cae0c..4d7e4402 100644 --- a/cli/src/templates/gitattributes +++ b/cli/src/templates/gitattributes @@ -6,7 +6,7 @@ src/parser.c linguist-generated src/tree_sitter/* linguist-generated # C bindings -bindings/c/* linguist-generated +bindings/c/** linguist-generated CMakeLists.txt linguist-generated Makefile linguist-generated diff --git a/cli/src/templates/makefile b/cli/src/templates/makefile index 36f00d2b..ddb47821 100644 --- a/cli/src/templates/makefile +++ b/cli/src/templates/makefile @@ -71,7 +71,7 @@ $(PARSER): $(SRC_DIR)/grammar.json install: all install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/PARSER_NAME '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' - install -m644 bindings/c/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h + install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) diff --git a/docs/src/cli/init.md b/docs/src/cli/init.md index 44e6b380..2751b368 100644 --- a/docs/src/cli/init.md +++ b/docs/src/cli/init.md @@ -126,7 +126,7 @@ to be used from different language. Here is a list of these bindings files that - `Makefile` — This file tells [`make`][make] how to compile your language. - `CMakeLists.txt` — This file tells [`cmake`][cmake] how to compile your language. -- `bindings/c/tree-sitter-language.h` — This file provides the C interface of your language. +- `bindings/c/tree_sitter/tree-sitter-language.h` — This file provides the C interface of your language. - `bindings/c/tree-sitter-language.pc` — This file provides [pkg-config][pkg-config] metadata about your language's C library. - `src/tree_sitter/parser.h` — This file provides some basic C definitions that are used in your generated `parser.c` file. - `src/tree_sitter/alloc.h` — This file provides some memory allocation macros that are to be used in your external scanner,