diff --git a/docs/README.instructions.md b/docs/README.instructions.md index 150365f..fd72db8 100644 --- a/docs/README.instructions.md +++ b/docs/README.instructions.md @@ -68,6 +68,7 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for | [Kotlin MCP Server Development Guidelines](../instructions/kotlin-mcp-server.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fkotlin-mcp-server.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fkotlin-mcp-server.instructions.md) | Best practices and patterns for building Model Context Protocol (MCP) servers in Kotlin using the official io.modelcontextprotocol:kotlin-sdk library. | | [Kubernetes Deployment Best Practices](../instructions/kubernetes-deployment-best-practices.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fkubernetes-deployment-best-practices.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fkubernetes-deployment-best-practices.instructions.md) | Comprehensive best practices for deploying and managing applications on Kubernetes. Covers Pods, Deployments, Services, Ingress, ConfigMaps, Secrets, health checks, resource limits, scaling, and security contexts. | | [LangChain Python Instructions](../instructions/langchain-python.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flangchain-python.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flangchain-python.instructions.md) | Instructions for using LangChain with Python | +| [Makefile Development Instructions](../instructions/makefile.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmakefile.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmakefile.instructions.md) | Best practices for authoring GNU Make Makefiles | | [Markdown](../instructions/markdown.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmarkdown.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmarkdown.instructions.md) | Documentation and content creation standards | | [Memory Bank](../instructions/memory-bank.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmemory-bank.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fmemory-bank.instructions.md) | Bank specific coding standards and best practices | | [Microsoft 365 Declarative Agents Development Guidelines](../instructions/declarative-agents-microsoft365.instructions.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdeclarative-agents-microsoft365.instructions.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdeclarative-agents-microsoft365.instructions.md) | Comprehensive development guidelines for Microsoft 365 Copilot declarative agents with schema v1.5, TypeSpec integration, and Microsoft 365 Agents Toolkit workflows | diff --git a/instructions/makefile.instructions.md b/instructions/makefile.instructions.md new file mode 100644 index 0000000..45b5bad --- /dev/null +++ b/instructions/makefile.instructions.md @@ -0,0 +1,410 @@ +--- +description: "Best practices for authoring GNU Make Makefiles" +applyTo: "**/Makefile, **/makefile, **/*.mk, **/GNUmakefile" +--- + +# Makefile Development Instructions + +Instructions for writing clean, maintainable, and portable GNU Make Makefiles. These instructions are based on the [GNU Make manual](https://www.gnu.org/software/make/manual/). + +## General Principles + +- Write clear and maintainable makefiles that follow GNU Make conventions +- Use descriptive target names that clearly indicate their purpose +- Keep the default goal (first target) as the most common build operation +- Prioritize readability over brevity when writing rules and recipes +- Add comments to explain complex rules, variables, or non-obvious behavior + +## Naming Conventions + +- Name your makefile `Makefile` (recommended for visibility) or `makefile` +- Use `GNUmakefile` only for GNU Make-specific features incompatible with other make implementations +- Use standard variable names: `objects`, `OBJECTS`, `objs`, `OBJS`, `obj`, or `OBJ` for object file lists +- Use uppercase for built-in variable names (e.g., `CC`, `CFLAGS`, `LDFLAGS`) +- Use descriptive target names that reflect their action (e.g., `clean`, `install`, `test`) + +## File Structure + +- Place the default goal (primary build target) as the first rule in the makefile +- Group related targets together logically +- Define variables at the top of the makefile before rules +- Use `.PHONY` to declare targets that don't represent files +- Structure makefiles with: variables, then rules, then phony targets + +```makefile +# Variables +CC = gcc +CFLAGS = -Wall -g +objects = main.o utils.o + +# Default goal +all: program + +# Rules +program: $(objects) + $(CC) -o program $(objects) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +# Phony targets +.PHONY: clean all +clean: + rm -f program $(objects) +``` + +## Variables and Substitution + +- Use variables to avoid duplication and improve maintainability +- Define variables with `:=` (simple expansion) for immediate evaluation, `=` for recursive expansion +- Use `?=` to set default values that can be overridden +- Use `+=` to append to existing variables +- Reference variables with `$(VARIABLE)` not `$VARIABLE` (unless single character) +- Use automatic variables (`$@`, `$<`, `$^`, `$?`, `$*`) in recipes to make rules more generic + +```makefile +# Simple expansion (evaluates immediately) +CC := gcc + +# Recursive expansion (evaluates when used) +CFLAGS = -Wall $(EXTRA_FLAGS) + +# Conditional assignment +PREFIX ?= /usr/local + +# Append to variable +CFLAGS += -g +``` + +## Rules and Prerequisites + +- Separate targets, prerequisites, and recipes clearly +- Use implicit rules for standard compilations (e.g., `.c` to `.o`) +- List prerequisites in logical order (normal prerequisites before order-only) +- Use order-only prerequisites (after `|`) for directories and dependencies that shouldn't trigger rebuilds +- Include all actual dependencies to ensure correct rebuilds +- Avoid circular dependencies between targets +- Remember that order-only prerequisites are omitted from automatic variables like `$^`, so reference them explicitly if needed + +The example below shows a pattern rule that compiles objects into an `obj/` directory. The directory itself is listed as an order-only prerequisite so it is created before compiling but does not force recompilation when its timestamp changes. + +```makefile +# Normal prerequisites +program: main.o utils.o + $(CC) -o $@ $^ + +# Order-only prerequisites (directory creation) +obj/%.o: %.c | obj + $(CC) $(CFLAGS) -c $< -o $@ + +obj: + mkdir -p obj +``` + +## Recipes and Commands + +- Start every recipe line with a **tab character** (not spaces) unless `.RECIPEPREFIX` is changed +- Use `@` prefix to suppress command echoing when appropriate +- Use `-` prefix to ignore errors for specific commands (use sparingly) +- Combine related commands with `&&` or `;` on the same line when they must execute together +- Keep recipes readable; break long commands across multiple lines with backslash continuation +- Use shell conditionals and loops within recipes when needed + +```makefile +# Silent command +clean: + @echo "Cleaning up..." + @rm -f $(objects) + +# Ignore errors +.PHONY: clean-all +clean-all: + -rm -rf build/ + -rm -rf dist/ + +# Multi-line recipe with proper continuation +install: program + install -d $(PREFIX)/bin && \ + install -m 755 program $(PREFIX)/bin +``` + +## Phony Targets + +- Always declare phony targets with `.PHONY` to avoid conflicts with files of the same name +- Use phony targets for actions like `clean`, `install`, `test`, `all` +- Place phony target declarations near their rule definitions or at the end of the makefile + +```makefile +.PHONY: all clean test install + +all: program + +clean: + rm -f program $(objects) + +test: program + ./run-tests.sh + +install: program + install -m 755 program $(PREFIX)/bin +``` + +## Pattern Rules and Implicit Rules + +- Use pattern rules (`%.o: %.c`) for generic transformations +- Leverage built-in implicit rules when appropriate (GNU Make knows how to compile `.c` to `.o`) +- Override implicit rule variables (like `CC`, `CFLAGS`) rather than rewriting the rules +- Define custom pattern rules only when built-in rules are insufficient + +```makefile +# Use built-in implicit rules by setting variables +CC = gcc +CFLAGS = -Wall -O2 + +# Custom pattern rule for special cases +%.pdf: %.md + pandoc $< -o $@ +``` + +## Splitting Long Lines + +- Use backslash-newline (`\`) to split long lines for readability +- Be aware that backslash-newline is converted to a single space in non-recipe contexts +- In recipes, backslash-newline preserves the line continuation for the shell +- Avoid trailing whitespace after backslashes + +### Splitting Without Adding Whitespace + +If you need to split a line without adding whitespace, you can use a special technique: insert `$ ` (dollar-space) followed by a backslash-newline. The `$ ` refers to a variable with a single-space name, which doesn't exist and expands to nothing, effectively joining the lines without inserting a space. + +```makefile +# Concatenate strings without adding whitespace +# The following creates the value "oneword" +var := one$ \ + word + +# This is equivalent to: +# var := oneword +``` + +```makefile +# Variable definition split across lines +sources = main.c \ + utils.c \ + parser.c \ + handler.c + +# Recipe with long command +build: $(objects) + $(CC) -o program $(objects) \ + $(LDFLAGS) \ + -lm -lpthread +``` + +## Including Other Makefiles + +- Use `include` directive to share common definitions across makefiles +- Use `-include` (or `sinclude`) to include optional makefiles without errors +- Place `include` directives after variable definitions that may affect included files +- Use `include` for shared variables, pattern rules, or common targets + +```makefile +# Include common settings +include config.mk + +# Include optional local configuration +-include local.mk +``` + +## Conditional Directives + +- Use conditional directives (`ifeq`, `ifneq`, `ifdef`, `ifndef`) for platform or configuration-specific rules +- Place conditionals at the makefile level, not within recipes (use shell conditionals in recipes) +- Keep conditionals simple and well-documented + +```makefile +# Platform-specific settings +ifeq ($(OS),Windows_NT) + EXE_EXT = .exe +else + EXE_EXT = +endif + +program: main.o + $(CC) -o program$(EXE_EXT) main.o +``` + +## Automatic Prerequisites + +- Generate header dependencies automatically rather than maintaining them manually +- Use compiler flags like `-MMD` and `-MP` to generate `.d` files with dependencies +- Include generated dependency files with `-include $(deps)` to avoid errors if they don't exist + +```makefile +objects = main.o utils.o +deps = $(objects:.o=.d) + +# Include dependency files +-include $(deps) + +# Compile with automatic dependency generation +%.o: %.c + $(CC) $(CFLAGS) -MMD -MP -c $< -o $@ +``` + +## Error Handling and Debugging + +- Use `$(error text)` or `$(warning text)` functions for build-time diagnostics +- Test makefiles with `make -n` (dry run) to see commands without executing +- Use `make -p` to print the database of rules and variables for debugging +- Validate required variables and tools at the beginning of the makefile + +```makefile +# Check for required tools +ifeq ($(shell which gcc),) + $(error "gcc is not installed or not in PATH") +endif + +# Validate required variables +ifndef VERSION + $(error VERSION is not defined) +endif +``` + +## Clean Targets + +- Always provide a `clean` target to remove generated files +- Declare `clean` as phony to avoid conflicts with a file named "clean" +- Use `-` prefix with `rm` commands to ignore errors if files don't exist +- Consider separate `clean` (removes objects) and `distclean` (removes all generated files) targets + +```makefile +.PHONY: clean distclean + +clean: + -rm -f $(objects) + -rm -f $(deps) + +distclean: clean + -rm -f program config.mk +``` + +## Portability Considerations + +- Avoid GNU Make-specific features if portability to other make implementations is required +- Use standard shell commands (prefer POSIX shell constructs) +- Test with `make -B` to force rebuild all targets +- Document any platform-specific requirements or GNU Make extensions used + +## Performance Optimization + +- Use `:=` for variables that don't need recursive expansion (faster) +- Avoid unnecessary use of `$(shell ...)` which creates subprocesses +- Order prerequisites efficiently (most frequently changing files last) +- Use parallel builds (`make -j`) safely by ensuring targets don't conflict + +## Documentation and Comments + +- Add a header comment explaining the makefile's purpose +- Document non-obvious variable settings and their effects +- Include usage examples or targets in comments +- Add inline comments for complex rules or platform-specific workarounds + +```makefile +# Makefile for building the example application +# +# Usage: +# make - Build the program +# make clean - Remove generated files +# make install - Install to $(PREFIX) +# +# Variables: +# CC - C compiler (default: gcc) +# PREFIX - Installation prefix (default: /usr/local) + +# Compiler and flags +CC ?= gcc +CFLAGS = -Wall -Wextra -O2 + +# Installation directory +PREFIX ?= /usr/local +``` + +## Special Targets + +- Use `.PHONY` for non-file targets +- Use `.PRECIOUS` to preserve intermediate files +- Use `.INTERMEDIATE` to mark files as intermediate (automatically deleted) +- Use `.SECONDARY` to prevent deletion of intermediate files +- Use `.DELETE_ON_ERROR` to remove targets if recipe fails +- Use `.SILENT` to suppress echoing for all recipes (use sparingly) + +```makefile +# Don't delete intermediate files +.SECONDARY: + +# Delete targets if recipe fails +.DELETE_ON_ERROR: + +# Preserve specific files +.PRECIOUS: %.o +``` + +## Common Patterns + +### Standard Project Structure + +```makefile +CC = gcc +CFLAGS = -Wall -O2 +objects = main.o utils.o parser.o + +.PHONY: all clean install + +all: program + +program: $(objects) + $(CC) -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + -rm -f program $(objects) + +install: program + install -d $(PREFIX)/bin + install -m 755 program $(PREFIX)/bin +``` + +### Managing Multiple Programs + +```makefile +programs = prog1 prog2 prog3 + +.PHONY: all clean + +all: $(programs) + +prog1: prog1.o common.o + $(CC) -o $@ $^ + +prog2: prog2.o common.o + $(CC) -o $@ $^ + +prog3: prog3.o + $(CC) -o $@ $^ + +clean: + -rm -f $(programs) *.o +``` + +## Anti-Patterns to Avoid + +- Don't start recipe lines with spaces instead of tabs +- Avoid hardcoding file lists when they can be generated with wildcards or functions +- Don't use `$(shell ls ...)` to get file lists (use `$(wildcard ...)` instead) +- Avoid complex shell scripts in recipes (move to separate script files) +- Don't forget to declare phony targets as `.PHONY` +- Avoid circular dependencies between targets +- Don't use recursive make (`$(MAKE) -C subdir`) unless absolutely necessary