alelievr / libft-unit-test

457 stars 88 forks source link

unable to compile because of the flag used (make -j 3 re) despite compiling perfectly when done myself with the same flags, can't explain it myself #30

Closed runiArnsbjornson closed 7 years ago

runiArnsbjornson commented 7 years ago

unable to compile because of the flag used (make -j 3 re) despite compiling perfectly when done myself with the same flags, can't explain it myself

runiArnsbjornson commented 7 years ago

screen shot 2017-05-03 at 10 52 13 am

alelievr commented 7 years ago

Hello

This behaviour is created by the way the -j x mullti-thread option works. It's pretty simple: when -j is active the makefile take the rule you ask to execute, look for dependencies (in this case the re dependencies are fclean and all) and run them in different threads concurently so fclean and all rule will be executed at the same time.

The problem is in case of a re, the fclean rule must be always executed before the all rule, if it's not the case the all rule will just do nothing or recompile missing .o files but not all because fclean does not have finished to remove all the object files.

the way to fix this is to change the re rule like this:

re:
    @$(MAKE) fclean
    @$(MAKE) all

Doing this, the multi-thread option will just act on the all rule because there is nothing to multi-thread in this re rule.

runiArnsbjornson commented 7 years ago

So what you are saying is you should never put a dependancy like this :

re : clean all @echo \033[32mRe done\033[0m

should the same be done on other make rules ? like the fclean (which has the clean rules dependancy) ? and put it like this :

fclean : @$(MAKE) clean @rm -rf $(NAME) @echo \033[31m Clean done\033[0m

it's pretty hard to find good explanation on the complex parts of makefiles, sorry if i bother with trivials questions

2017-05-03 13:55 GMT+02:00 alelievr notifications@github.com:

Hello

This behaviour is created by the way the -j x mullti-thread option works. It's pretty simple: when -j is active the makefile take the rule you ask to execute, look for dependencies (in this case the re dependencies are fclean and all) and run them in different threads concurently so fclean and all rule will be executed at the same time.

The problem is in case of a re, the fclean rule must be always executed before the all rule, if it's not the case the all rule will just do nothing or recompile missing .o files but not all because fclean does not have finished to remove all the object files.

the way to fix this is to change the re rule like this:

re: @$(MAKE) fclean @$(MAKE) all

Doing this, the multi-thread option will just act on the all rule because there is nothing to multi-thread in this re rule.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/alelievr/libft-unit-test/issues/30#issuecomment-298890172, or mute the thread https://github.com/notifications/unsubscribe-auth/AVOZERyO3diz0FDUVz9lxyTkeEHhC2FRks5r2GshgaJpZM4NPHL7 .

alelievr commented 7 years ago

There is no problem to put dependencies on fclean rule because we don't matter if an object/executable is deleted before another.
It's the same for the all rule with all your object files as dependencies, you just want all your source file to be compiled no matter the order so it's not a problem if -j run them concurrently or in a random order.

You need to care about dependencies only when you absolutely want one to be executed bore another:

task1:
    @touch test

task2:
    @test -r && echo "Hello world !" > test

task3:
    @cat test

task4:
    @rm test

task: task1 task2 task3 task4

In this Makefile, the task rule call in order the taskX dependencies, and they are design to work only if the previous is done.
Here is the result with and without -j option:

As you can see, with -j option, it's a undefined behaviour and without it's stable.
To fix this use @$(MAKE) rule as i said before but if you you have a list of dependencies which not require the previous to be done it's useless:

 task1:
     rm -f src1.o

 task2:
     rm -f src2.o

 task3:
     rm -f src3.o

 task4:
     rm -f src4.o

 task: task1 task2 task3 task4

This will work perfectly with or without -j option because you can change the dependencies order: if you write task: task4 task3 task1 task2 this will not change the final result which is not the case for the re rule: if i write re: all fclean it will not work.

I hope my explanations are not too unclear, here is a pretty good article describing the problem: https://www.cmcrossroads.com/article/pitfalls-and-benefits-gnu-make-parallelization