JUSTOCASOU
This commit is contained in:
parent
c358562ecc
commit
5b820a5ade
8 changed files with 220 additions and 41 deletions
|
|
@ -7,7 +7,7 @@ DBG_LDFLAGS= -fsanitize=address
|
||||||
|
|
||||||
|
|
||||||
SRC_DIR = src
|
SRC_DIR = src
|
||||||
LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c
|
LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c files/files.c
|
||||||
MAIN_SRCS = main.c minimake.c
|
MAIN_SRCS = main.c minimake.c
|
||||||
|
|
||||||
# SRCS = $(patsubst %,$(SRC_DIR)/%, $(MAIN_SRCS))
|
# SRCS = $(patsubst %,$(SRC_DIR)/%, $(MAIN_SRCS))
|
||||||
|
|
|
||||||
99
minimake/src/files/files.c
Normal file
99
minimake/src/files/files.c
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
#include "files.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// #include "../lines/lines.h"
|
||||||
|
|
||||||
|
char *get_makefile(struct list *files)
|
||||||
|
{
|
||||||
|
struct list *file = files;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
// Test file presence
|
||||||
|
while (file != NULL && !found)
|
||||||
|
{
|
||||||
|
FILE *test = fopen(file->data, "r");
|
||||||
|
if (test != NULL)
|
||||||
|
{
|
||||||
|
fclose(test);
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file = file->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *res = NULL;
|
||||||
|
if (found)
|
||||||
|
res = file->data;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t get_file_lastmodiftime(char *filename)
|
||||||
|
{
|
||||||
|
struct stat stat;
|
||||||
|
if (lstat(filename, &stat) == -1)
|
||||||
|
return -1;
|
||||||
|
return stat.st_mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls a shell that will run the given command
|
||||||
|
// It will first print the command to run unless the it starts with '@'
|
||||||
|
// Returns the return code o the command or -1 if a syscall fails
|
||||||
|
int run_command(char *command)
|
||||||
|
{
|
||||||
|
if (command[0] == '@')
|
||||||
|
command++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
puts(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just in case
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
// char *executable;
|
||||||
|
// size_t args_offset = readword(command, strlen(command), &executable);
|
||||||
|
|
||||||
|
int id = fork();
|
||||||
|
if (id < 0)
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
wait(&res);
|
||||||
|
// printf("Got return code: %d\n", res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int res = execl("/bin/sh", "(make)", "-c", command, NULL);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 1 if file exists (and is readable), 0 otherwise
|
||||||
|
int file_exists(char *filename)
|
||||||
|
{
|
||||||
|
if (filename == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FILE *test = fopen(filename, "r");
|
||||||
|
if (test == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fclose(test);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
14
minimake/src/files/files.h
Normal file
14
minimake/src/files/files.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef FILES_H
|
||||||
|
#define FILES_H
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE 500
|
||||||
|
|
||||||
|
#include "../lists/lists.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
char* get_makefile(struct list *files);
|
||||||
|
ssize_t get_file_lastmodiftime(char* filename);
|
||||||
|
int run_command(char *command);
|
||||||
|
int file_exists(char *filename);
|
||||||
|
|
||||||
|
#endif // FILES_H
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "files/files.h"
|
||||||
#include "lists/lists.h"
|
#include "lists/lists.h"
|
||||||
#include "minimake.h"
|
#include "minimake.h"
|
||||||
|
|
||||||
|
|
@ -58,10 +59,12 @@ static int handle_args(int argc, char **argv, struct list **minimake_files,
|
||||||
else if (strcmp(argv[i], "-f") == 0)
|
else if (strcmp(argv[i], "-f") == 0)
|
||||||
{
|
{
|
||||||
flags |= FLAGS_CUSTOM_FILE;
|
flags |= FLAGS_CUSTOM_FILE;
|
||||||
if (i + 1 == argc || argv[i + 1][0] == '-')
|
i++;
|
||||||
|
|
||||||
|
if (i == argc || argv[i][0] == '-')
|
||||||
errx(INVALID_ARG, "No file specified after '-f'");
|
errx(INVALID_ARG, "No file specified after '-f'");
|
||||||
|
|
||||||
files = list_prepend(files, argv[i + 1]);
|
files = list_prepend(files, argv[i]);
|
||||||
}
|
}
|
||||||
// Print
|
// Print
|
||||||
else if (strcmp(argv[i], "-p") == 0)
|
else if (strcmp(argv[i], "-p") == 0)
|
||||||
|
|
@ -92,33 +95,6 @@ static int handle_args(int argc, char **argv, struct list **minimake_files,
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_makefile(struct list *files)
|
|
||||||
{
|
|
||||||
struct list *file = files;
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
// Test file presence
|
|
||||||
while (file != NULL && !found)
|
|
||||||
{
|
|
||||||
FILE *test = fopen(file->data, "r");
|
|
||||||
if (test != NULL)
|
|
||||||
{
|
|
||||||
fclose(test);
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file = file->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *res = NULL;
|
|
||||||
if (found)
|
|
||||||
res = file->data;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct list *files;
|
struct list *files;
|
||||||
|
|
@ -129,8 +105,8 @@ int main(int argc, char **argv)
|
||||||
if (filename == NULL)
|
if (filename == NULL)
|
||||||
errx(GENERIC_ERR, "No Makefile found");
|
errx(GENERIC_ERR, "No Makefile found");
|
||||||
|
|
||||||
make(filename, flags, argv[0]);
|
int res = make(filename, rules, argv[0], flags);
|
||||||
list_destroy(files);
|
list_destroy(files);
|
||||||
list_destroy(rules);
|
list_destroy(rules);
|
||||||
return 0;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "files/files.h"
|
||||||
#include "hash_maps/hash_maps.h"
|
#include "hash_maps/hash_maps.h"
|
||||||
#include "lines/lines.h"
|
#include "lines/lines.h"
|
||||||
#include "lists/lists.h"
|
#include "lists/lists.h"
|
||||||
|
|
@ -459,21 +460,103 @@ void make_parse(char *path)
|
||||||
|
|
||||||
// ==== Runtime ====
|
// ==== Runtime ====
|
||||||
|
|
||||||
// static void make_run(void)
|
// Expands and run a specified rule
|
||||||
// {}
|
static int run_rule(struct rule *rule)
|
||||||
|
{
|
||||||
|
struct list *commands = rule->recipe;
|
||||||
|
struct list *dependencies = rule->dependencies;
|
||||||
|
|
||||||
|
// Expand dependencies variables
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Build dependencies
|
||||||
|
while (dependencies != NULL)
|
||||||
|
{
|
||||||
|
// Check file existence
|
||||||
|
if (!file_exists(dependencies->data))
|
||||||
|
{
|
||||||
|
// Check rule existence instead
|
||||||
|
struct rule *dep_rule = hashmap_get(rules, dependencies->data);
|
||||||
|
if (dep_rule != NULL)
|
||||||
|
{
|
||||||
|
int res = run_rule(dep_rule);
|
||||||
|
if (res != 0) // Exit on error
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drop(GENERIC_ERR, "No rule to make target '%s'",
|
||||||
|
dependencies->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (commands != NULL)
|
||||||
|
{
|
||||||
|
// Expand command variables
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Run
|
||||||
|
int res = run_command(commands->data);
|
||||||
|
if (res != 0) // Exit on error
|
||||||
|
return res;
|
||||||
|
|
||||||
|
commands = commands->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the given rules after parsing
|
||||||
|
int make_run(struct list *given_rules)
|
||||||
|
{
|
||||||
|
if (given_rules == NULL)
|
||||||
|
{
|
||||||
|
// No rule specified => run first rule found in the Makefile
|
||||||
|
if (rules_list == NULL)
|
||||||
|
drop(GENERIC_ERR, "No targets");
|
||||||
|
|
||||||
|
struct rule *full_rule = hashmap_get(rules, rules_list->data);
|
||||||
|
if (full_rule == NULL)
|
||||||
|
drop(GENERIC_ERR,
|
||||||
|
"Internal error: Could not retrieve target '%s' in database",
|
||||||
|
rules_list->data);
|
||||||
|
|
||||||
|
return run_rule(full_rule);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (given_rules != NULL)
|
||||||
|
{
|
||||||
|
struct rule *full_rule = hashmap_get(rules, given_rules->data);
|
||||||
|
if (full_rule == NULL)
|
||||||
|
drop(GENERIC_ERR, "No rule to make target '%s'",
|
||||||
|
given_rules->data);
|
||||||
|
|
||||||
|
int res = run_rule(full_rule);
|
||||||
|
if (res != 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
given_rules = given_rules->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==== MAKE ====
|
// ==== MAKE ====
|
||||||
|
|
||||||
void make(char *path, int flags, char *argv0)
|
int make(char *path, struct list *rules, char *exec_name, int flags)
|
||||||
{
|
{
|
||||||
program_name = argv0;
|
program_name = exec_name;
|
||||||
|
|
||||||
make_parse(path);
|
make_parse(path);
|
||||||
|
|
||||||
if (flags & FLAGS_PRINT)
|
if (flags & FLAGS_PRINT)
|
||||||
dump_database();
|
dump_database();
|
||||||
|
|
||||||
|
int status = make_run(rules);
|
||||||
free_all();
|
free_all();
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints an error message before exiting gracefully (by freeing all variables)
|
// Prints an error message before exiting gracefully (by freeing all variables)
|
||||||
|
|
@ -482,9 +565,9 @@ void drop(int status, char *format, ...)
|
||||||
// Print
|
// Print
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
fprintf(stderr, "%s: ", program_name);
|
fprintf(stderr, "%s: *** ", program_name);
|
||||||
vfprintf(stderr, format, args);
|
vfprintf(stderr, format, args);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, ". Stop.\n");
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
free_all();
|
free_all();
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@
|
||||||
#define FLAGS_PRINT 2
|
#define FLAGS_PRINT 2
|
||||||
|
|
||||||
// Default values
|
// Default values
|
||||||
#define DEFAULT_MAKEFILE "Makefile"
|
#define DEFAULT_MAKEFILE "makefile"
|
||||||
#define DEFAULT_MAKEFILE_2 "makefile"
|
#define DEFAULT_MAKEFILE_2 "Makefile"
|
||||||
#define BUFFER_SIZE 1024
|
#define BUFFER_SIZE 1024
|
||||||
#define HASHMAP_SIZE 32
|
#define HASHMAP_SIZE 32
|
||||||
|
|
||||||
|
|
@ -38,8 +38,9 @@ struct rule
|
||||||
struct list *recipe;
|
struct list *recipe;
|
||||||
};
|
};
|
||||||
|
|
||||||
void make(char *path, int flags, char* program_name);
|
int make(char *path, struct list* rules, char *argv0, int flags);
|
||||||
void make_parse(char *path);
|
void make_parse(char *path);
|
||||||
|
int make_run(struct list *rules);
|
||||||
void drop(int status, char *format, ...);
|
void drop(int status, char *format, ...);
|
||||||
void dump_database(void);
|
void dump_database(void);
|
||||||
size_t expand_variable(struct line *line, size_t index, char **value);
|
size_t expand_variable(struct line *line, size_t index, char **value);
|
||||||
|
|
|
||||||
1
minimake/tests/Makefile.test3
Normal file
1
minimake/tests/Makefile.test3
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
VAR = 1
|
||||||
5
minimake/tests/Makefile.test4
Normal file
5
minimake/tests/Makefile.test4
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
rule1:
|
||||||
|
echo Toto
|
||||||
|
|
||||||
|
rule2:
|
||||||
|
@echo Toto
|
||||||
Loading…
Add table
Add a link
Reference in a new issue