makefile instructions
Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com>
This commit is contained in:
parent
5bf1f4d8b8
commit
12a1ed2ddf
@ -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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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)<br />[](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 |
|
||||
|
||||
410
instructions/makefile.instructions.md
Normal file
410
instructions/makefile.instructions.md
Normal file
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user