Skip to content

Follow Makefile includes when completing make targets#275

Open
maxmilian wants to merge 1 commit into
warpdotdev:mainfrom
maxmilian:maxmilian/fix-11705-make-includes
Open

Follow Makefile includes when completing make targets#275
maxmilian wants to merge 1 commit into
warpdotdev:mainfrom
maxmilian:maxmilian/fix-11705-make-includes

Conversation

@maxmilian
Copy link
Copy Markdown

Summary

Fixes warpdotdev/warp#11705. make Tab-completion only suggested targets defined directly in the top-level Makefile; targets pulled in through include directives were invisible (other terminals show them, since GNU make treats included files as one unified ruleset).

Root cause

The make list_targets generator (command-signatures/src/generators/make.rs) ran cat [Mm]akefile, which reads only the root Makefile and never follows include / -include / sinclude directives.

Fix

Replace the command with a single self-contained awk program that echoes the root Makefile and recurses into included files, with a seen set guarding against include cycles. Design choices:

  • All parsing happens inside awk (not a shell loop), so behavior is identical across the user's shell — sh/bash/zsh differ in word-splitting and this sidesteps that entirely.
  • Injection-safe: included paths are opened directly via getline < path, never interpolated into a shell command, so a malicious Makefile can't inject commands.
  • Fallback: awk output is captured and only emitted on a clean exit; otherwise it falls back to the original cat [Mm]akefile. An include pointing at a real directory (an invalid Makefile that make itself rejects) aborts some awk builds with an i/o error — the fallback keeps top-level targets working instead of returning nothing.

The Rust post_process (target + ## description parsing) is unchanged.

Tests

Two end-to-end tests run the actual generator command via sh -c against temp projects:

  • test_list_targets_command_follows_includes — targets split across a nested include + a missing optional -include; also asserts a ## description defined in an included file survives.
  • test_list_targets_command_survives_directory_include — a directory include still succeeds and falls back to top-level targets.

cargo fmt --check, cargo clippy --all-targets --all-features -- -D warnings, and cargo test all pass locally (61 tests).

Scope / known limitations

Include paths that rely on globbing (include dir/*.mk) or make variables (include $(VAR)) are intentionally left unresolved — expanding them safely would require either a shell (injection risk) or evaluating the Makefile. Explicit file paths (the reported case and the common case) and arbitrarily nested includes are handled.

The `make` `list_targets` generator ran `cat [Mm]akefile`, which reads
only the top-level Makefile, so targets defined in files pulled in via
`include`/`-include`/`sinclude` were never suggested (warpdotdev/warp#11705).

Replace the command with a self-contained awk program that echoes the
root Makefile and recurses into included files, using a `seen` set to
guard against include cycles. Included paths are opened directly with
`getline` rather than interpolated into a shell command, so a Makefile
cannot inject commands. The behavior is identical across sh/bash/zsh
because all parsing happens inside awk, not via shell word-splitting.

awk output is captured and only emitted on a clean exit; otherwise the
command falls back to `cat [Mm]akefile`. This keeps top-level targets
working when an `include` points at a real directory (an invalid
Makefile that aborts some awk builds with an i/o error) instead of
returning nothing.

Glob (`include dir/*.mk`) and variable (`include $(VAR)`) include paths
are intentionally left unresolved.

Add end-to-end tests that run the generator command against temp
projects: one with targets split across a nested include and a missing
optional include (also asserting `##` descriptions survive), and one
with a directory include to lock in the fallback.
@maxmilian maxmilian force-pushed the maxmilian/fix-11705-make-includes branch from adb42f0 to 1c60a56 Compare May 29, 2026 03:22
@maxmilian maxmilian marked this pull request as ready for review May 29, 2026 03:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Autocomplete for make doesn't work when Makefile uses include

1 participant