diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-08-31 00:28:00 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-08-31 12:04:19 +0900 |
| commit | da65f1e21a24f0a173ee5ae08f00db91cba5ffda (patch) | |
| tree | 3ec802f40d7cd0bd9e162ea5b3e50b76f319a884 | |
| parent | a5ee9d944edf665c814bbfeded2849f2bb980ed8 (diff) | |
| download | ducc-da65f1e21a24f0a173ee5ae08f00db91cba5ffda.tar.gz ducc-da65f1e21a24f0a173ee5ae08f00db91cba5ffda.tar.zst ducc-da65f1e21a24f0a173ee5ae08f00db91cba5ffda.zip | |
feat: support -MMD flag
| -rw-r--r-- | Makefile | 14 | ||||
| -rw-r--r-- | justfile | 5 | ||||
| -rw-r--r-- | src/cli.c | 8 | ||||
| -rw-r--r-- | src/cli.h | 1 | ||||
| -rw-r--r-- | src/fs.c | 26 | ||||
| -rw-r--r-- | src/fs.h | 7 | ||||
| -rw-r--r-- | src/io.c | 7 | ||||
| -rw-r--r-- | src/main.c | 21 | ||||
| -rw-r--r-- | src/preprocess.c | 33 | ||||
| -rw-r--r-- | src/preprocess.h | 3 | ||||
| -rw-r--r-- | src/std.h | 1 |
11 files changed, 99 insertions, 27 deletions
@@ -1,6 +1,7 @@ SRC_DIR := src -BUILD_DIR := build TARGET ?= ducc +BUILD_ROOT_DIR := build +BUILD_DIR := $(BUILD_ROOT_DIR)/.$(TARGET) OBJECTS := \ $(BUILD_DIR)/main.o \ @@ -8,6 +9,7 @@ OBJECTS := \ $(BUILD_DIR)/cli.o \ $(BUILD_DIR)/codegen.o \ $(BUILD_DIR)/common.o \ + $(BUILD_DIR)/fs.o \ $(BUILD_DIR)/io.o \ $(BUILD_DIR)/json.o \ $(BUILD_DIR)/parse.o \ @@ -17,15 +19,15 @@ OBJECTS := \ $(BUILD_DIR)/tokenize.o .PHONY: all -all: $(BUILD_DIR) $(BUILD_DIR)/$(TARGET) - -$(BUILD_DIR)/$(TARGET): $(OBJECTS) - $(CC) -MD -g -O0 -o $@ $^ +all: $(BUILD_DIR) $(BUILD_ROOT_DIR)/$(TARGET) $(BUILD_DIR): @mkdir -p $(BUILD_DIR) +$(BUILD_ROOT_DIR)/$(TARGET): $(OBJECTS) + $(CC) -MMD -g -O0 -o $@ $^ + $(BUILD_DIR)/%.o: src/%.c - $(CC) -c -MD -g -O0 -o $@ $< + $(CC) -c -MMD -g -O0 -o $@ $< -include $(BUILD_DIR)/*.d @@ -1,5 +1,3 @@ -all: build - build N="1": #!/usr/bin/env bash set -e @@ -13,8 +11,7 @@ build N="1": cc="./build/ducc$(({{N}} - 1))" target=ducc{{N}} fi - # TODO: Remove --always-make once ducc supports -MD. - CC="$cc" TARGET="$target" make --always-make + CC="$cc" TARGET="$target" make build-upto-5-gen: just build 1 @@ -5,6 +5,7 @@ CliArgs* parse_cli_args(int argc, char** argv) { const char* output_filename = NULL; int positional_arguments_start = -1; BOOL only_compile = FALSE; + BOOL generate_deps = FALSE; for (int i = 1; i < argc; ++i) { if (argv[i][0] != '-') { @@ -16,8 +17,8 @@ CliArgs* parse_cli_args(int argc, char** argv) { // ignore } else if (c == 'O') { // ignore - } else if (c == 'M') { - // ignore + } else if (c == 'M' && argv[i][2] == '\0') { + // ignore -M } else if (c == 'o') { if (argc <= i + 1) { fatal_error("-o requires filename"); @@ -26,6 +27,8 @@ CliArgs* parse_cli_args(int argc, char** argv) { ++i; } else if (c == 'c') { only_compile = TRUE; + } else if (strcmp(argv[i], "-MMD") == 0) { + generate_deps = TRUE; } else { fatal_error("unknown option: %s", argv[i]); } @@ -41,6 +44,7 @@ CliArgs* parse_cli_args(int argc, char** argv) { a->only_compile = only_compile; a->totally_deligate_to_gcc = FALSE; a->gcc_command = NULL; + a->generate_deps = generate_deps; if (!a->only_compile && str_ends_with(a->input_filename, ".o")) { a->totally_deligate_to_gcc = TRUE; @@ -8,6 +8,7 @@ struct CliArgs { const char* output_filename; BOOL output_assembly; BOOL only_compile; + BOOL generate_deps; BOOL totally_deligate_to_gcc; const char* gcc_command; }; diff --git a/src/fs.c b/src/fs.c new file mode 100644 index 0000000..a299ef9 --- /dev/null +++ b/src/fs.c @@ -0,0 +1,26 @@ +#include "fs.h" +#include "std.h" + +// 'ext' must include '.'. +char* replace_extension(const char* file_name, const char* ext) { + size_t len = strlen(file_name); + const char* last_slash = strrchr(file_name, '/'); + const char* last_dot = strrchr(file_name, '.'); + + size_t ext_len = strlen(ext); + size_t base_len; + // !last_slash: foo.c + // last_slash < last_dot: ./bar/foo.c + if (last_dot && (!last_slash || last_slash < last_dot)) { + base_len = last_dot - file_name; + } else { + base_len = len; + } + + char* result = calloc(base_len + ext_len + 1, sizeof(char)); + memcpy(result, file_name, base_len); + memcpy(result + base_len, ext, ext_len); + result[base_len + ext_len] = '\0'; + + return result; +} diff --git a/src/fs.h b/src/fs.h new file mode 100644 index 0000000..b71889f --- /dev/null +++ b/src/fs.h @@ -0,0 +1,7 @@ +#ifndef DUCC_FS_H +#define DUCC_FS_H + +// 'ext' must include '.'. +char* replace_extension(const char* file_name, const char* ext); + +#endif @@ -14,12 +14,7 @@ void sourcelocation_build_json(JsonBuilder* builder, SourceLocation* loc) { } InFile* infile_open(const char* filename) { - FILE* in; - if (strcmp(filename, "-") == 0) { - in = stdin; - } else { - in = fopen(filename, "rb"); - } + FILE* in = fopen(filename, "rb"); if (!in) { return NULL; } @@ -2,6 +2,7 @@ #include "cli.h" #include "codegen.h" #include "common.h" +#include "fs.h" #include "io.h" #include "parse.h" #include "preprocess.h" @@ -16,7 +17,11 @@ int main(int argc, char** argv) { } InFile* source = infile_open(cli_args->input_filename); - TokenArray* pp_tokens = preprocess(source); + + StrArray included_files; + strings_init(&included_files); + + TokenArray* pp_tokens = preprocess(source, &included_files); TokenArray* tokens = tokenize(pp_tokens); Program* prog = parse(tokens); @@ -45,4 +50,18 @@ int main(int argc, char** argv) { fatal_error("gcc failed: %d", result); } } + + if (cli_args->generate_deps && cli_args->only_compile && cli_args->output_filename) { + const char* dep_filename = replace_extension(cli_args->output_filename, ".d"); + + FILE* dep_file = fopen(dep_filename, "w"); + if (!dep_file) { + fatal_error("Cannot open dependency file: %s", dep_filename); + } + fprintf(dep_file, "%s:", cli_args->output_filename); + for (size_t i = 0; i < included_files.len; ++i) { + fprintf(dep_file, " \\\n %s", included_files.data[i]); + } + fprintf(dep_file, "\n"); + } } diff --git a/src/preprocess.c b/src/preprocess.c index 284a633..03a2121 100644 --- a/src/preprocess.c +++ b/src/preprocess.c @@ -559,12 +559,14 @@ struct Preprocessor { int include_depth; char** include_paths; int n_include_paths; + StrArray* included_files; }; typedef struct Preprocessor Preprocessor; -static TokenArray* do_preprocess(InFile* src, int depth, MacroArray* macros); +static TokenArray* do_preprocess(InFile* src, int depth, MacroArray* macros, StrArray* included_files); -static Preprocessor* preprocessor_new(TokenArray* pp_tokens, int include_depth, MacroArray* macros) { +static Preprocessor* preprocessor_new(TokenArray* pp_tokens, int include_depth, MacroArray* macros, + StrArray* included_files) { if (include_depth >= 32) { fatal_error("include depth limit exceeded"); } @@ -574,6 +576,7 @@ static Preprocessor* preprocessor_new(TokenArray* pp_tokens, int include_depth, pp->macros = macros; pp->include_depth = include_depth; pp->include_paths = calloc(16, sizeof(char*)); + pp->included_files = included_files; return pp; } @@ -745,7 +748,8 @@ static void expand_include_directive(Preprocessor* pp, const char* include_name, original_include_name_tok->loc.line, token_stringify(original_include_name_tok)); } - TokenArray* include_pp_tokens = do_preprocess(include_source, pp->include_depth + 1, pp->macros); + TokenArray* include_pp_tokens = + do_preprocess(include_source, pp->include_depth + 1, pp->macros, pp->included_files); tokens_pop(include_pp_tokens); // pop EOF token pp->pos = insert_pp_tokens(pp, pp->pos, include_pp_tokens); } @@ -1119,6 +1123,20 @@ static void preprocess_include_directive(Preprocessor* pp) { fatal_error("%s:%d: cannot resolve include file name: %s", include_name->loc.filename, include_name->loc.line, token_stringify(include_name)); } + + if (include_name->value.string[0] == '"') { + BOOL already_included = FALSE; + for (size_t i = 0; i < pp->included_files->len; ++i) { + if (strcmp(pp->included_files->data[i], include_name_resolved) == 0) { + already_included = TRUE; + break; + } + } + if (!already_included) { + strings_push(pp->included_files, include_name_resolved); + } + } + skip_whitespaces(pp); expect_pp_token(pp, TokenKind_newline); expand_include_directive(pp, include_name_resolved, include_name); @@ -1379,9 +1397,9 @@ static char* get_ducc_include_path() { return buf; } -static TokenArray* do_preprocess(InFile* src, int depth, MacroArray* macros) { +static TokenArray* do_preprocess(InFile* src, int depth, MacroArray* macros, StrArray* included_files) { TokenArray* pp_tokens = pp_tokenize(src); - Preprocessor* pp = preprocessor_new(pp_tokens, depth, macros); + Preprocessor* pp = preprocessor_new(pp_tokens, depth, macros, included_files); add_include_path(pp, get_ducc_include_path()); add_include_path(pp, "/usr/include/x86_64-linux-gnu"); add_include_path(pp, "/usr/include"); @@ -1390,8 +1408,9 @@ static TokenArray* do_preprocess(InFile* src, int depth, MacroArray* macros) { return pp->pp_tokens; } -TokenArray* preprocess(InFile* src) { +TokenArray* preprocess(InFile* src, StrArray* included_files) { MacroArray* macros = macros_new(); add_predefined_macros(macros); - return do_preprocess(src, 0, macros); + strings_push(included_files, src->loc.filename); + return do_preprocess(src, 0, macros, included_files); } diff --git a/src/preprocess.h b/src/preprocess.h index b43ec4c..81007c3 100644 --- a/src/preprocess.h +++ b/src/preprocess.h @@ -1,9 +1,10 @@ #ifndef DUCC_PREPROCESS_H #define DUCC_PREPROCESS_H +#include "common.h" #include "io.h" #include "token.h" -TokenArray* preprocess(InFile* src); +TokenArray* preprocess(InFile* src, StrArray* included_files); #endif @@ -34,6 +34,7 @@ int strncmp(const char*, const char*, size_t); char* strdup(const char*); char* strndup(const char*, size_t); char* strstr(const char*, const char*); +char* strrchr(const char*, int); long strtol(const char*, char**, int); int system(const char*); |
