实验代码框架讲解

本节目录

项目结构

.
├── exercises //所有习题都在此文件夹下
├── LICENSE
├── Makefile
├── README.en.md
├── README.md
└── test //所有测例都在此文件夹下
  • exercises:这个文件夹包含了所有的习题代码。每个习题可以作为一个子文件夹,其中包含习题的源代码、数据文件和任何相关的资源。
  • LICENSE:项目的许可证文件,定义了项目的使用、修改和分发的法律条款。
  • Makefile:一个自动化构建脚本,用于编译、测试和清理项目。通过运行 make 命令,可以执行 Makefile 中定义的任务。
  • test:这个文件夹包含了所有的测试用例。每个测试用例可以作为一个子文件夹或文件,用于验证习题代码的正确性。

Makefile 内容

实验框架的 Makefile:

# Makefile variables for directory structure and tools
AUX_DIR     := aux             # Auxiliary directory
BUILD_DIR   := build           # Build output directory
SRC_DIR     := src             # Source code directory
RESULT_DIR  := result          # Test result directory
TEST_DIR    := test            # Directory containing test scripts

# Compiler settings
CC ?= gcc                       # Default compiler

# Compiler flags
CFLAGS = -std=c11 -Wall -Wextra -Wpedantic -Werror -g  # C compiler flags
LDFLAGS = -Wl,--as-needed -Wl,--no-undefined          # Linker flags

# Find all exercise directories under SRC_DIR
EXERCISES := $(shell find $(SRC_DIR) -type d -name 'exercise-*' -exec basename {} \;)

# Default target: build all exercises
all: $(EXERCISES)

# Build each exercise directory
$(EXERCISES):
    @mkdir -p $(abspath $(BUILD_DIR))/$(notdir $@)
    $(MAKE) -C $(SRC_DIR)/$@ OUTPUT_DIR=$(abspath $(BUILD_DIR))/$(notdir $@) || true

# Test target: run tests for all exercises
test: $(RESULT_DIR) $(EXERCISES:%=test-%) report generate_json_report

# Test each exercise
test-%: $(BUILD_DIR)/%
    @mkdir -p $(RESULT_DIR)/$*
    @echo "Running tests for $*"
    @$(TEST_DIR)/$*/test.sh $(BUILD_DIR)/$*/$* && touch $(RESULT_DIR)/$*/$*.pass || touch $(RESULT_DIR)/$*/$*.fail

# Create build directory if it doesn't exist
$(BUILD_DIR):
    @mkdir -p $(BUILD_DIR)

# Create result directory if it doesn't exist
$(RESULT_DIR):
    @mkdir -p $(RESULT_DIR)

# Generate a human-readable test report
report:
    @echo "Generating test report..."
    @total=$$(find $(RESULT_DIR) -type f -name '*.pass' -o -name '*.fail' | wc -l); \
    success=$$(find $(RESULT_DIR) -type f -name '*.pass' | wc -l); \
    failed=$$(find $(RESULT_DIR) -type f -name '*.fail' | wc -l); \
    echo "Total tests: $$total"; \
    echo "Success: $$success"; \
    echo "Failed: $$failed"; \
    echo "Success tests:"; \
    find $(RESULT_DIR) -type f -name '*.pass' -exec basename {} .pass \; | sed 's/^/  /'; \
    echo "Failed tests:"; \
    find $(RESULT_DIR) -type f -name '*.fail' -exec basename {} .fail \; | sed 's/^/  /'

# Generate a JSON test report
generate_json_report:
    @echo "Generating JSON report..."
    @success=$$(find $(RESULT_DIR) -type f -name '*.pass' | wc -l); \
    score=$$((success * 5)); \
    total_score=100; \
    channel="gitee"; \
    course_id=1546; \
    ext="aaa"; \
    name=""; \
    echo '{' > $(RESULT_DIR)/report.json; \
    echo '  "channel": "'$$channel'"'',' >> $(RESULT_DIR)/report.json; \
    echo '  "courseId": ' $$course_id',' >> $(RESULT_DIR)/report.json; \
    echo '  "ext": "'$$ext'"'',' >> $(RESULT_DIR)/report.json; \
    echo '  "name": "'$$name'"'',' >> $(RESULT_DIR)/report.json; \
    echo '  "score": ' $$score',' >> $(RESULT_DIR)/report.json; \
    echo '  "totalScore": ' $$total_score >> $(RESULT_DIR)/report.json; \
    echo '}' >> $(RESULT_DIR)/report.json;

# Clean target: remove all generated files and directories
clean:
    for dir in $(EXERCISES); do \
        $(MAKE) -C $$dir clean; \
    done
    rm -rf $(BUILD_DIR) $(RESULT_DIR)

# Declare phony targets to prevent conflicts with file names
.PHONY: all clean $(EXERCISES) report generate_json_report
  • 目录定义
    • EXERCISE_DIR:存放练习文件的目录。
    • TEST_DIR:存放测试文件的目录。
    • BUILD_DIR:存放构建产物的目录。
  • 文件和目录操作
    • mkdir -p $(TEST_DIR) $(BUILD_DIR):确保测试和构建目录存在。
  • 编译和链接
    • CC = gcc:定义编译器为 gcc。
    • CFLAGS = -Wall -Wextra -std=c99:编译选项,包括警告和 C99 标准。
    • LDFLAGS = -lm:链接选项,链接数学库。
  • 构建规则
    • $(BUILD_DIR)/%: $(EXERCISE_DIR)/%.c:为每个练习文件生成对应的执行文件。
  • 清理规则
    • clean:删除所有执行文件和构建目录下的对象文件。
  • 测试规则
    • generate-test-cases:生成测试用例。
    • test-output:运行测试并比较输出结果。
    • save-test-results:保存测试结果和通过率到 JSON 文件。

使用 makefile 进行实验

在实验过程中,Makefile 提供了自动化构建和测试的便利。以下是如何使用这个 Makefile 进行实验的步骤:

  1. 编译所有练习

    make
    

    这个命令会编译所有练习文件,并在BUILD_DIR目录下生成对应的执行文件。

  2. 生成测试用例

    make generate-test-cases
    

    这个命令会运行所有执行文件,并将输出保存为测试用例。

  3. 运行测试

    make test-output
    

    这个命令会比较每个执行文件的输出与预期结果,并显示测试结果。

  4. 保存测试结果

    make save-test-results
    

    这个命令会计算测试的通过率,并将结果保存到test_results.json文件中。

  5. 清理

    make clean
    

    这个命令会删除所有构建产物和对象文件,保持环境整洁。