diff --git a/bakefile.jar b/bakefile.jar index a268f9a..4e01078 100644 Binary files a/bakefile.jar and b/bakefile.jar differ diff --git a/src/fr/monlouyan/bakefile/BakeCLI.java b/src/fr/monlouyan/bakefile/BakeCLI.java index 34d1981..b909324 100644 --- a/src/fr/monlouyan/bakefile/BakeCLI.java +++ b/src/fr/monlouyan/bakefile/BakeCLI.java @@ -20,7 +20,7 @@ public class BakeCLI { /* * Liste des arguments passés en ligne de commande */ - private List<String> targets; + private static List<String> targets; /** * Constructeur de la classe BakeCLI @@ -31,7 +31,7 @@ public class BakeCLI { */ public BakeCLI(String[] args){ debug = false; - this.targets = new ArrayList<>(); + targets = new ArrayList<>(); parseArgs(args); } @@ -60,5 +60,5 @@ public class BakeCLI { * Permet de récupérer les arguments autres que "-d" passés en ligne de commande * @return */ - public List<String> getTargets(){ return targets; } + public static List<String> getTargets(){ return targets; } } diff --git a/src/fr/monlouyan/bakefile/BakeEngine.java b/src/fr/monlouyan/bakefile/BakeEngine.java index 574058b..8306fa0 100644 --- a/src/fr/monlouyan/bakefile/BakeEngine.java +++ b/src/fr/monlouyan/bakefile/BakeEngine.java @@ -3,13 +3,11 @@ package fr.monlouyan.bakefile; import java.util.List; public class BakeEngine { - private BakeCLI cli; private BakefileParser parser; private DependencyResolver resolver; private CommandExecutor executor; - public BakeEngine(BakeCLI cli) { - this.cli = cli; + public BakeEngine() { this.parser = new BakefileParser("Bakefile"); this.resolver = new DependencyResolver(BakeCLI.isDebug()); this.executor = new CommandExecutor(BakeCLI.isDebug()); @@ -17,7 +15,7 @@ public class BakeEngine { public void run() { List<Rule> rules = parser.parse(); - List<Rule> rulesToBuild = resolver.resolve(rules, cli.getTargets()); + List<Rule> rulesToBuild = resolver.resolve(rules, BakeCLI.getTargets()); for (Rule rule : rulesToBuild) { executor.execute(rule); diff --git a/src/fr/monlouyan/bakefile/BakefileParser.java b/src/fr/monlouyan/bakefile/BakefileParser.java index 6202da4..9659613 100644 --- a/src/fr/monlouyan/bakefile/BakefileParser.java +++ b/src/fr/monlouyan/bakefile/BakefileParser.java @@ -8,6 +8,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class BakefileParser { + /** + * Nom du fichier Bakefile à parser (donc Bakefile...). + */ private String filename; /** @@ -22,8 +25,15 @@ public class BakefileParser { */ private static final Pattern COMMAND_PATTERN = Pattern.compile("^\\s+(.+)$"); + /** + * Première cible trouvée dans le fichier Bakefile. + */ + private static String firstTarget; + + public BakefileParser(String filename) { this.filename = filename; + firstTarget = null; } public List<Rule> parse() { @@ -46,6 +56,10 @@ public class BakefileParser { Matcher commandMatcher = COMMAND_PATTERN.matcher(line); if (targetMatcher.matches()) { + if (firstTarget == null) { + firstTarget = targetMatcher.group(1); + } + // Sauvegarde de la règle précédente si elle existe if (currentTarget != null) { rules.add(new Rule(currentTarget, dependencies, commands, phonyTargets.contains(currentTarget))); @@ -71,4 +85,10 @@ public class BakefileParser { } return rules; } + + /** + * Permet de récupérer la première cible trouvée dans le fichier Bakefile. + * @return La première cible trouvée + */ + public static String getFirstTarget() { return firstTarget; } } diff --git a/src/fr/monlouyan/bakefile/CommandExecutor.java b/src/fr/monlouyan/bakefile/CommandExecutor.java index 786ecd3..0779d65 100644 --- a/src/fr/monlouyan/bakefile/CommandExecutor.java +++ b/src/fr/monlouyan/bakefile/CommandExecutor.java @@ -15,11 +15,14 @@ public class CommandExecutor { return; } - if (!rule.needsUpdate()){ - System.out.println("bake: '" + rule.getName() + "' is up to date."); + if (!rule.needsUpdate()) { + if (rule.getName().equals(BakefileParser.getFirstTarget())) { + System.out.println("bake: '" + rule.getName() + "' is up to date."); + } return; } + try { for (String command : rule.getCommands()) { System.out.println(command); // Affichage de la commande executée diff --git a/src/fr/monlouyan/bakefile/DependencyResolver.java b/src/fr/monlouyan/bakefile/DependencyResolver.java index 8ca21fc..e47a015 100644 --- a/src/fr/monlouyan/bakefile/DependencyResolver.java +++ b/src/fr/monlouyan/bakefile/DependencyResolver.java @@ -1,26 +1,80 @@ package fr.monlouyan.bakefile; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class DependencyResolver { private boolean debug; - + private Map<String, Rule> ruleMap; + public DependencyResolver(boolean debug) { this.debug = debug; } public List<Rule> resolve(List<Rule> allRules, List<String> requestedRules) { List<Rule> rulesToBuild = new ArrayList<>(); + ruleMap = new HashMap<>(); + Set<String> builtRules = new HashSet<>(); // Éviter d'ajouter des règles déjà vérifiées for (Rule rule : allRules) { - if (requestedRules.isEmpty() || requestedRules.contains(rule.getName()) || rule.isPhony()) { - if (debug){ - System.out.println("Rule " + rule.getName() + " is requested"); - } - rulesToBuild.add(rule); + ruleMap.put(rule.getName(), rule); + } + + Set<String> visited = new HashSet<>(); + Set<String> stack = new HashSet<>(); + + for (String ruleName : requestedRules.isEmpty() ? ruleMap.keySet() : requestedRules) { + if (ruleMap.containsKey(ruleName)) { + detectCycle(ruleName, visited, stack); + collectDependencies(ruleName, rulesToBuild, builtRules); + } else if (debug) { + System.out.println("Warning: Rule '" + ruleName + "' not found."); } } + return rulesToBuild; } -} \ No newline at end of file + + /** + * Détection des cycles avec DFS + */ + private void detectCycle(String ruleName, Set<String> visited, Set<String> stack) { + if (stack.contains(ruleName)) { + throw new RuntimeException("Dependency cycle detected involving rule: " + ruleName); + } + + if (!visited.contains(ruleName)) { + visited.add(ruleName); + stack.add(ruleName); + + Rule rule = ruleMap.get(ruleName); + if (rule != null) { + for (String dependency : rule.getDependencies()) { + if (ruleMap.containsKey(dependency)) { + detectCycle(dependency, visited, stack); + } + } + } + stack.remove(ruleName); + } + } + + /** + * Collecte récursive des règles à construire en évitant les doublons + */ + private void collectDependencies(String ruleName, List<Rule> rulesToBuild, Set<String> builtRules) { + if (builtRules.contains(ruleName)) { + return; // Évite d'ajouter une règle plusieurs fois + } + + Rule rule = ruleMap.get(ruleName); + if (rule != null) { + for (String dependency : rule.getDependencies()) { + if (ruleMap.containsKey(dependency)) { + collectDependencies(dependency, rulesToBuild, builtRules); + } + } + rulesToBuild.add(rule); + builtRules.add(ruleName); + } + } +} diff --git a/src/fr/monlouyan/bakefile/Main.java b/src/fr/monlouyan/bakefile/Main.java index 9bc4c09..3f455f1 100755 --- a/src/fr/monlouyan/bakefile/Main.java +++ b/src/fr/monlouyan/bakefile/Main.java @@ -16,8 +16,9 @@ public class Main{ * @return void */ public static void main(String[] args){ + @SuppressWarnings("unused") BakeCLI cli = new BakeCLI(args); - BakeEngine engine = new BakeEngine(cli); + BakeEngine engine = new BakeEngine(); engine.run(); } } \ No newline at end of file diff --git a/tests/bakefile.jar b/tests/bakefile.jar index a268f9a..4e01078 100644 Binary files a/tests/bakefile.jar and b/tests/bakefile.jar differ diff --git a/tests/test-01-depuis-rien/bakefile.jar b/tests/test-01-depuis-rien/bakefile.jar index a268f9a..4e01078 100644 Binary files a/tests/test-01-depuis-rien/bakefile.jar and b/tests/test-01-depuis-rien/bakefile.jar differ diff --git a/tests/test-02-existe-deja/bakefile.jar b/tests/test-02-existe-deja/bakefile.jar index a268f9a..4e01078 100644 Binary files a/tests/test-02-existe-deja/bakefile.jar and b/tests/test-02-existe-deja/bakefile.jar differ diff --git a/tests/test-03-circulaire/Bakefile b/tests/test-03-circulaire/Bakefile index b458a3d..c43de20 100644 --- a/tests/test-03-circulaire/Bakefile +++ b/tests/test-03-circulaire/Bakefile @@ -2,10 +2,10 @@ main: a b c gcc a b c -o main a: a.c a.h b.h - gcc -Wall -Werror -Wextra -Pendatic -c a.c -o a + gcc -Wall -Werror -Wextra -ansi -pedantic -c a.c -o a b: b.c b.h c.h - gcc -Wall -Werror -Wextra -Pendatic -c b.c -o b + gcc -Wall -Werror -Wextra -ansi -pedantic -c b.c -o b c: c.c c.h a.h - gcc -Wall -Werror -Wextra -Pendatic -c c.c -o c + gcc -Wall -Werror -Wextra -ansi -pedantic -c c.c -o c diff --git a/tests/test-03-circulaire/README.md b/tests/test-03-circulaire/README.md index abaa797..6a847eb 100644 --- a/tests/test-03-circulaire/README.md +++ b/tests/test-03-circulaire/README.md @@ -1,3 +1,15 @@ -# Test 3 : Dépendances circulaire +# Test 3 : Gestion des dépendances circulaires +## Description +Ce test vérifie que le système de compilation peut détecter et gérer correctement les dépendances circulaires. Il simule un projet où plusieurs fichiers `.c` et `.h` s'incluent mutuellement, créant ainsi une boucle dans les dépendances. +## Fichiers utilisés +- `a.c` : Implémente functionA qui appelle functionB. +- `b.c` : Implémente functionB qui appelle functionC. +- `c.c` : Implémente functionC et inclut a.h, créant une boucle indirecte. +- `a.h`, `b.h`, `c.h` : Fichiers d'en-tête correspondant. +- `Bakefile` : Contient les règles de compilation et les dépendances. +- `bakefile.jar` : Version compilée de notre système de build. + +## Résultat attendu +Si le système de build détecte une dépendance circulaire, il doit la gérer automatiquement en évitant la boucle infinie et en compilant correctement les fichiers. \ No newline at end of file diff --git a/tests/test-03-circulaire/a.c b/tests/test-03-circulaire/a.c index 3f49efe..283d470 100644 --- a/tests/test-03-circulaire/a.c +++ b/tests/test-03-circulaire/a.c @@ -1,12 +1,12 @@ #include <stdio.h> #include "b.h" -void functionA() { - printf("Function A called\n"); - functionB(); // Appelle une fonction de b.c +void functionA(void) { + printf("Fonction A appelée\n"); + functionB(); } -int main() { +int main(void) { functionA(); return 0; } diff --git a/tests/test-03-circulaire/a.h b/tests/test-03-circulaire/a.h index d53839a..f043ff5 100644 --- a/tests/test-03-circulaire/a.h +++ b/tests/test-03-circulaire/a.h @@ -1,6 +1,6 @@ #ifndef A_H #define A_H -void functionA(); +void functionA(void); #endif diff --git a/tests/test-03-circulaire/b.c b/tests/test-03-circulaire/b.c index b7da733..6be825f 100644 --- a/tests/test-03-circulaire/b.c +++ b/tests/test-03-circulaire/b.c @@ -1,7 +1,7 @@ #include <stdio.h> #include "c.h" -void functionB() { - printf("Function B called\n"); - functionC(); // Appelle une fonction de c.c +void functionB(void) { + printf("Fonction B appelée\n"); + functionC(); } diff --git a/tests/test-03-circulaire/b.h b/tests/test-03-circulaire/b.h index 321af19..622ae55 100644 --- a/tests/test-03-circulaire/b.h +++ b/tests/test-03-circulaire/b.h @@ -1,6 +1,6 @@ #ifndef B_H #define B_H -void functionB(); +void functionB(void); #endif diff --git a/tests/test-03-circulaire/bakefile.jar b/tests/test-03-circulaire/bakefile.jar index a268f9a..4e01078 100644 Binary files a/tests/test-03-circulaire/bakefile.jar and b/tests/test-03-circulaire/bakefile.jar differ diff --git a/tests/test-03-circulaire/c.c b/tests/test-03-circulaire/c.c index 7e53ed3..aee51b0 100644 --- a/tests/test-03-circulaire/c.c +++ b/tests/test-03-circulaire/c.c @@ -1,7 +1,8 @@ #include <stdio.h> +#include <stdlib.h> #include "a.h" -void functionC() { - printf("Function C called\n"); - functionA(); // Appelle une fonction de a.c -> dépendance circulaire +void functionC(void) { + printf("Fonction C appelée\n"); + return; } diff --git a/tests/test-03-circulaire/c.h b/tests/test-03-circulaire/c.h index be34ba5..312d6d6 100644 --- a/tests/test-03-circulaire/c.h +++ b/tests/test-03-circulaire/c.h @@ -1,6 +1,6 @@ #ifndef C_H #define C_H -void functionC(); +void functionC(void); #endif