diff --git a/README.md b/README.md deleted file mode 100644 index 7cc185b..0000000 --- a/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Minimake - -Minimake is a small project written in about a week in C99. Its goal was to reproduce the main features of the well known GNU Make utility. - -> **Note** This is a school project, therefore it probably won't interest you if you are looking for something useful. - -## Build - -```sh -make -``` -or even better -```sh -minimake -``` - -## How it works - -If you're not familiar with Make, what it does is that it reads a file named -`Makefile` in the current directory which contains instructions to build a -project in the form of recipes. It includes support for variables, dependencies -, implicit rules and more. - -Then depending on the user input it automatically executes a recipe with its dependencies. - - -Here is what a basic one can look like -```make -BENCH_FLAGS = --all - -test_and_bench: - bash ./runtests.sh - bash ./runbenchs.sh $(BENCH_FLAGS) -``` - -But it will more realisticly look like that - -```make -CC = gcc -CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla -LDFLAGS= - -DBG_CFLAGS = -fsanitize=address -g -DBG_LDFLAGS= -fsanitize=address - - -SRC_DIR = src -LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c files/files.c -MAIN_SRCS = main.c minimake.c - -SRCS = $(MAIN_SRCS:%=$(SRC_DIR)/%) $(LIB_SRCS:%=$(SRC_DIR)/%) -OBJS = $(SRCS:.c=.o) - -TARGET= minimake -DBG_TARGET = minimake-dbg - -$(TARGET): $(OBJS) - $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) - @echo $(OBJS) - -debug: CFLAGS += $(DBG_CFLAGS) -debug: LDFLAGS += $(DBG_LDFLAGS) -debug: $(OBJS) - $(CC) -o $(DBG_TARGET) $^ $(LDFLAGS) $(LDLIBS) - -check: - dash ./tests/run.sh - -clean: - $(RM) $(TARGET) - $(RM) $(OBJS) - -``` diff --git a/micromake/src/Microfile b/micromake/src/Microfile new file mode 100644 index 0000000..607b02a --- /dev/null +++ b/micromake/src/Microfile @@ -0,0 +1,3 @@ +qwertyu: +cbejw: a bc d +dmwq :d wdwd diff --git a/micromake/src/micromake.c b/micromake/src/micromake.c new file mode 100644 index 0000000..fda3fe2 --- /dev/null +++ b/micromake/src/micromake.c @@ -0,0 +1,119 @@ +#define _POSIX_C_SOURCE 200809L +#define BUFFER_SIZE 1024 +#define STRING_BUFFER_SIZE 32 + +#include +#include +#include +#include + +// Helps to match a string (excludes blanks and special characters) +static int is_char(char c) +{ + return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; +} + +// Returns the next word from buf until buf_len, +// and the numbers of read characters in *read_chars +// WARNING allocates the result on the heap +static char *readWord(char *buf, size_t buf_len, size_t *read_chars) +{ + size_t i = 0; + size_t str_buf_size = STRING_BUFFER_SIZE; + char *str_buf = malloc(sizeof(char) * str_buf_size); + while (i < buf_len && is_char(buf[i])) + { + // Reallocate more space if necessary + if (i >= str_buf_size - 1) + { + str_buf_size += STRING_BUFFER_SIZE; + str_buf = realloc(str_buf, str_buf_size); + if (str_buf == NULL) + errx(2, "Could not realloc"); + } + + str_buf[i] = buf[i]; + i++; + } + + str_buf[i] = '\0'; + *read_chars = i; + + return str_buf; +} + +int skip_blanks(char *buf, size_t buf_len) +{ + size_t i = 0; + while (i < buf_len && isblank(buf[i])) + i++; + return i; +} + +int main(int argc, char **argv) +{ + if (argc < 2) + errx(2, "Not enough arguments"); + if (argc > 2) + errx(2, "Not enough arguments"); + + // Open file + FILE *stream = fopen(argv[1], "r"); + if (stream == 0) + errx(2, "Could not open file"); + + // Allocate buffer + size_t buf_size = BUFFER_SIZE; + char *buf = malloc(sizeof(char) * buf_size); + if (buf == NULL) + errx(2, "Could not allocate more memory"); + + // Read + ssize_t nread; + while ((nread = getline(&buf, &buf_size, stream)) != -1) + { + size_t u_nread = nread; + size_t i = 0; + // Skip blanks + i += skip_blanks(buf + i, nread - i); + + // Read target name + size_t skipped_chars = 0; + char *rule_name = readWord(buf + i, nread - i, &skipped_chars); + if (skipped_chars != 0) + printf("%s:", rule_name); + i += skipped_chars; + + // Skip until ':' + i += skip_blanks(buf + i, nread - i); + if (buf[i] != ':') + errx(2, "Unexpected character '%c' after rule declaration '%s'", + buf[i], rule_name); + i++; + + // Read deps + while (i < u_nread) + { + // Skip blanks + i += skip_blanks(buf + i, nread - i); + + // Read word + size_t skipped_chars = 0; + char *dep_name = readWord(buf + i, nread - i, &skipped_chars); + if (skipped_chars != 0) + printf(" %s", dep_name); + free(dep_name); + i += skipped_chars; + + if (!is_char(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') + errx(2, "Unexpected character '%c'", buf[i]); + } + + i++; + free(rule_name); + } + + free(buf); + fclose(stream); + return 0; +} diff --git a/microshell/microshell.c b/microshell/microshell.c new file mode 100644 index 0000000..4a7b661 --- /dev/null +++ b/microshell/microshell.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + if (argc < 2) + err(1, "Not enough args"); + + int id = fork(); + if (id < 0) + err(1, "Cannot fork"); + + if (id == 0) + { + int res = 0; + wait(&res); + // printf("%d\n", res); + return res; + } + else + { + int res = execl("/bin/sh", "supershell", "-c", argv[1], NULL); + printf("process exit status: %d\n", res); + // exit(res); + return res; + } +} diff --git a/Makefile b/minimake/Makefile similarity index 81% rename from Makefile rename to minimake/Makefile index db29234..cb0ae0a 100644 --- a/Makefile +++ b/minimake/Makefile @@ -21,10 +21,10 @@ $(TARGET): $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) @echo $(OBJS) -debug: CFLAGS += $(DBG_CFLAGS) -debug: LDFLAGS += $(DBG_LDFLAGS) -debug: $(OBJS) - $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) +# debug: CFLAGS += $(DBG_CFLAGS) +# debug: LDFLAGS += $(DBG_LDFLAGS) +# debug: $(OBJS) +# $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) check: dash ./tests/run.sh diff --git a/src/files/files.c b/minimake/src/files/files.c similarity index 89% rename from src/files/files.c rename to minimake/src/files/files.c index b27627d..2d46ecb 100644 --- a/src/files/files.c +++ b/minimake/src/files/files.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,9 @@ int run_command(char *command) fflush(stdout); fflush(stderr); + // char *executable; + // size_t args_offset = readword(command, strlen(command), &executable); + int id = fork(); if (id < 0) { @@ -68,13 +72,14 @@ int run_command(char *command) if (id == 0) { - int res = execl("/bin/sh", "(make)", "-c", command, NULL); - exit(res); + int res = 0; + wait(&res); + // printf("Got return code: %d\n", res); + return res; } else { - int res = 0; - wait(&res); + int res = execl("/bin/sh", "(make)", "-c", command, NULL); return res; } } diff --git a/src/files/files.h b/minimake/src/files/files.h similarity index 100% rename from src/files/files.h rename to minimake/src/files/files.h diff --git a/src/hash_maps/hash_maps.c b/minimake/src/hash_maps/hash_maps.c similarity index 100% rename from src/hash_maps/hash_maps.c rename to minimake/src/hash_maps/hash_maps.c diff --git a/src/hash_maps/hash_maps.h b/minimake/src/hash_maps/hash_maps.h similarity index 100% rename from src/hash_maps/hash_maps.h rename to minimake/src/hash_maps/hash_maps.h diff --git a/src/lines/lines.c b/minimake/src/lines/lines.c similarity index 100% rename from src/lines/lines.c rename to minimake/src/lines/lines.c diff --git a/src/lines/lines.h b/minimake/src/lines/lines.h similarity index 100% rename from src/lines/lines.h rename to minimake/src/lines/lines.h diff --git a/src/lists/lists.c b/minimake/src/lists/lists.c similarity index 100% rename from src/lists/lists.c rename to minimake/src/lists/lists.c diff --git a/src/lists/lists.h b/minimake/src/lists/lists.h similarity index 100% rename from src/lists/lists.h rename to minimake/src/lists/lists.h diff --git a/src/main.c b/minimake/src/main.c similarity index 100% rename from src/main.c rename to minimake/src/main.c diff --git a/src/minimake.c b/minimake/src/minimake.c similarity index 92% rename from src/minimake.c rename to minimake/src/minimake.c index 4368296..c28aed3 100644 --- a/src/minimake.c +++ b/minimake/src/minimake.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "files/files.h" @@ -18,14 +17,14 @@ // Static variables -static char *program_name; +char *program_name; -static struct hash_map *variables = NULL; -static struct hash_map *rules = NULL; +struct hash_map *variables = NULL; +struct hash_map *rules = NULL; // Keeps track of variables and rules order -static struct list *variables_list = NULL; -static struct list *rules_list = NULL; +struct list *variables_list = NULL; +struct list *rules_list = NULL; // ==== Misc ==== @@ -338,7 +337,6 @@ size_t expand_variable(struct line *line, size_t index, char **value) // Get corresponding value *value = get_variable_value(var_name, line->number); - free(var_name); } return 2; @@ -462,42 +460,16 @@ void make_parse(char *path) // ==== Runtime ==== -// Return 1 if rule is up to date, 0 otherwise -static int uptodate(struct rule *rule) -{ - struct stat path_stat; - - if (lstat(rule->name, &path_stat) != 0) // target doesn't exists - return 0; - - struct list *dependencies = rule->dependencies; - while (dependencies != NULL) - { - char *depname = dependencies->data; - if (lstat(depname, &path_stat) != 0) // Dependecy doesn't exists - return 0; - } - return 1; -} - // Expands and run a specified rule static int run_rule(struct rule *rule) { - // Check if p to date - if (uptodate(rule)) - { - printf("%s: '%s' is up to date.", program_name, rule->name); - return 0; - } - struct list *commands = rule->recipe; struct list *dependencies = rule->dependencies; // Build dependencies while (dependencies != NULL) { - // Expand variable - // TODO + // Expand variables // Check file existence if (!file_exists(dependencies->data)) @@ -516,15 +488,6 @@ static int run_rule(struct rule *rule) dependencies->data); } } - - dependencies = dependencies->next; - } - - // Empty recipe - if (commands == NULL) - { - printf("%s: Nothing to be done for '%s'.\n", program_name, rule->name); - return 0; } while (commands != NULL) @@ -587,15 +550,9 @@ int make(char *path, struct list *rules, char *exec_name, int flags) make_parse(path); - // Print if (flags & FLAGS_PRINT) - { dump_database(); - free_all(); - return 0; - } - // Run int status = make_run(rules); free_all(); return status; @@ -633,7 +590,7 @@ void dump_database(void) // Print char *key = elt->data; - printf("'%s' = '%s'\n", key, val); + printf("%s = %s\n", key, val); elt = elt->next; } @@ -648,7 +605,7 @@ void dump_database(void) drop(GENERIC_ERR, "Could not get rule '%s' in database", elt->data); // Print name - printf("(%s):", rule->name); + printf("(%s) :", rule->name); // Print dependencies struct list *dep = rule->dependencies; diff --git a/src/minimake.h b/minimake/src/minimake.h similarity index 100% rename from src/minimake.h rename to minimake/src/minimake.h diff --git a/tests/Makefile.syntax-test b/minimake/tests/Makefile.syntax-test similarity index 100% rename from tests/Makefile.syntax-test rename to minimake/tests/Makefile.syntax-test diff --git a/tests/Makefile.test3 b/minimake/tests/Makefile.test3 similarity index 100% rename from tests/Makefile.test3 rename to minimake/tests/Makefile.test3 diff --git a/minimake/tests/Makefile.test4 b/minimake/tests/Makefile.test4 new file mode 100644 index 0000000..45ee423 --- /dev/null +++ b/minimake/tests/Makefile.test4 @@ -0,0 +1,5 @@ +rule1: + echo Toto + +rule2: + @echo Toto diff --git a/tests/Makefile2.syntax-test b/minimake/tests/Makefile2.syntax-test similarity index 100% rename from tests/Makefile2.syntax-test rename to minimake/tests/Makefile2.syntax-test diff --git a/tests/run.sh b/minimake/tests/run.sh similarity index 100% rename from tests/run.sh rename to minimake/tests/run.sh diff --git a/simple_ls/simple_ls.c b/simple_ls/simple_ls.c new file mode 100644 index 0000000..508c5df --- /dev/null +++ b/simple_ls/simple_ls.c @@ -0,0 +1,37 @@ +#include +#include +#include + +static void simple_ls(char *path) +{ + if (path == NULL) + errx(1, "Internal error: Passed NULL path"); + + DIR *dir = opendir(path); + if (dir == NULL) + errx(1, "Internal error: cannot open directory"); + + struct dirent *element; + while ((element = readdir(dir))) + { + puts(element->d_name); + } + + int res = closedir(dir); + if (res == -1) + errx(1, "Could not close dir"); +} + +int main(int argc, char **argv) +{ + if (argc < 2) + simple_ls("."); + else + { + for (int i = 1; i < argc; i++) + { + simple_ls(argv[i]); + } + } + return 0; +} diff --git a/tests/Makefile.empty b/tests/Makefile.empty deleted file mode 100644 index e9228f2..0000000 --- a/tests/Makefile.empty +++ /dev/null @@ -1 +0,0 @@ -empty_target: diff --git a/tests/Makefile.test4 b/tests/Makefile.test4 deleted file mode 100644 index 4da97dd..0000000 --- a/tests/Makefile.test4 +++ /dev/null @@ -1,7 +0,0 @@ -rule1: - echo Toto - echo Tata - echo Tutu - -rule2: - @echo Toto encore diff --git a/tests/Makefile.vars b/tests/Makefile.vars deleted file mode 100644 index b5ce417..0000000 --- a/tests/Makefile.vars +++ /dev/null @@ -1,4 +0,0 @@ -V=2 - -main: - echo $V