-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add checks for circular dependencies in cice.build #336
Add checks for circular dependencies in cice.build #336
Conversation
The circular dependency error message and behavior is likely compiler dependent. The grep implemented in the modifications is probably not general. We probably want to investigate further how to better trap circular dependencies across different compilers and platforms if that is important. The cleanbuild should be cleaning all .mod, .o, binaries, and the dependencies file. That should be correct and ensure builds are repeatable (and truly clean when rebuilding). If the clean build is not doing that, I think we should try to fix it, not try to trap a circular dependency error created by a bad clean build. |
Thanks for your feedback.
In fact it is an error message outputed by make, and not the compiler. You are right that I opened this PR quickly and did not try to make it as general as I should have. We already have an environment variable It don't think it's explicitly specified anywhere, bu I'm pretty sure that our Makefile uses GNU Make specific features, so it would not work with BSD make or AIX make or another make implementation (users on these platforms would have to install GNU Make to use our Makefile). So in that case we should just check that the error message outputed by GNU make is the same for different GNU make versions. (And probably we should mention in the user guide that GNU make is required for compiling CICE, maybe in a new 'System requirements' section)
The clean build works fine, that is what I tried to explain above, I might not have been clear enough. The different situations that I try to address are the following: A (incremental build)
B (clean build)
|
@phil-blain, thanks for the clarifications. Sorry for my confusion. For case A above, I think if anyone is modifying code and changing the dependencies, they should NOT be doing incremental builds. I don't believe the CICE make system will build the system properly in this case, and the circular dependency problem just seems to prove that it won't support that level of incremental build. The circular dependency problem is just one of many issues that can break when incremental builds are taken too far. I believe the incremental build is best used when small code changes are introduced during the development process. It should not be used for bigger changes, like dependency changes. Maybe we should improve the build process to make this all more robust, but I think there are tradeoffs to that approach and most people will just have cleanbuild on all the time which is the default. Rather than introduce extra checks, traps, and error messages in the build process to work around these issues, I suggest we try to make the incremental build limitations clearer in the documentation and/or add some checks in the build to do something like always run the dependency generator and compare that output to the prior build and have the build stop (or clean automatically) if the dependency changes. Again, I think what we want to do is discourage incremental builds when dependencies change. And if we do that, then the extra check on the circular dependency is not needed. Having said that, I'm also willing to consider improving the robustness of the incremental build feature as the alternative. For case B, an extra error output can be added, although I'm not sure it's needed in this case as the error should be relatively clear in the build log file. I think changing the | to |& is a good idea. |
This problem still catches me from time to time, and I know students who have lost days because of it. Although it's not necessary and shouldn't ever happen, having an extra warning at the end of the compile sequence wouldn't hurt, if the script can be made general enough to work for all compilers. I also agree that stronger language in the documentation regarding incremental builds would be wise. |
There are several tasks that come out of this
It's not clear to me that the extra error message is really needed in case B. The model will fail as soon as the circular dependence is encountered and it will be the "last error" in the build log file. That seems adequate. It's really case A that creates havoc and is more difficult to detect. My preference is to close this PR and work on the two bullets above. I'm happy to take those on. Alternatively we could merge this PR, but I would like to be able to remove the extra error messages when the bullets above are addressed. A final alternative is we keep this open and continue to develop. I could PR some changes to @phil-blain's branch to help this evolve. Lets make a plan. @eclare108213 @phil-blain what do you think? |
I have a few comments :
I disagree: the build system works perfectly fine in incremental mode if the user introduces new dependencies (the automatic dependency generation runs each time make is run and it works correctly). I use it all the time this way, and never have any problem. The thing is it just does not prevent the user from introducing circular dependencies. I think it should; the build should detect circular dependencies and simply abort with a clear error message if it finds some. I don't think that automatically cleaning if dependencies change is a good way forward.
Like @eclare108213 said, it can be easy to miss: the last message will be "module x not found", but one has to go to the beginning of the log file to find the "make : circular dependency dropped" message and from that infer that a circular dependency was introduced. |
So what I propose is : |
Also, I I think (I haven't check) that all these situations are already implemented in more advanced/modern build systems such as Cmake |
@phil-blain @apcraig |
OK, I'm starting to be convinced. Would it be possible to abort as soon as the circular dependency is detected? In other words, rather than having cice.build grep for a string in the build log and do something, could we add a check directly in the Makefile so as soon as the circular dependency is hit, it fails. That would take care of A and B and stop the compile where the error is obvious and never generate a binary. I have googled for a flag in gmake that might do that, but have not found anything yet. Could we add a rule to the Makefile? If so, I think that might be a cleaner way to handle it. @phil-blain, do you think that is possible/reasonable, and if so, do you have time to do some prototyping or would you like me to try to find some time? If that doesn't work, then I'm fine moving ahead with what @phil-blain is proposing. Separately, I agree that we might depend on gmake and should make that clear in our documentation. Whether we should switch to a different Make system is a reasonable question. gmake is generally the default make option on most systems or it's at least available and lots of folks are familiar with it. I think we have to ask the standard questions if we change to cmake; is it readily available, are people familiar with it, how much effort is it to change, how much will it cost longer term relative to not switching, how much benefit will it provide. I don't know the answer to all those questions, but we could look into it. |
I also googled for a flag to make make abort if it finds circular deps; I don't think it exists (make was originally developed more for C/C++ and with these languages circular deps are usually not fatal, usually they just come from a badly written makefile) I guess that is why make does not consider it a fatal error. It might me possible to write a rule, so that the general flow would be Regarding switching to another build system, all these questions are good ones. I know that CMake is becoming the industry standard pretty fast for C/C++, and that they (Kitware and the community) are committed to supporting Fortran also. I'm not familiar with it though, so I don't know how much of an effort it would be to port our build system to it. |
Thanks @phil-blain. If I get a chance, I might try a few things. My thinking was more along the lines of catching the "circular" dependence in the Makefile as part the build, not necessarily building some other logic. Some maybe in the .o: .F there is a rule we can add that can catch the circular dependence, even with a grep-like construct or something. It depends when that error is triggered in the make and whether we can catch it robustly. |
I played around with this branch a bit and now understand much better the issues and problems. I agree this is a valuable feature. Thanks @phil-blain for your patience with me. It is not possible for the Makefile to trap this because it's not an error that the actual build generates, it's an produced by gmake separate from the build. It's an interesting interaction. I am going to propose some changes via a PR to the branch in a few minutes,
The branch including the PR has been tested on conrad here, The documentation has been tested and can be reviewed here, add-circular-dep-warnings doc build. The main new documentation feature is the software requirements section. We'll have to try to remember to keep it up to date as much as possible, but it will never be complete and I think that's OK. Having something is better than nothing. |
Thanks @apcraig for the PR. I merged it and added 2 commits (mainly changes to capitalization in the doc). |
Thanks for the latest changes @phil-blain. And thanks again for suggesting this feature and being patient with me. I'll merge now. |
PR checklist
Add checks for circular dependencies in cice.build
Philippe Blain, Tony Craig
No tests - no changes to code
If while developing you introduce a circular dependency between modules, make will let you know when you run cice.build by outputing
make: Circular ice_domain.o <- ice_boundary.o dependency dropped.
but it does not stop (it is not a fatal error). This message can easily be overlooked since there is a lot of output from cice.build.Moreover, it is even possible for the build to succeed when ICE_CLEANBUILD is set to false since the modules files already exists. The build is most probably broken in this case because make did not recompile everything that changed sinced it dropped dependencies. If you try a clean build in that case it will always fail.
I added a check in cice.build to directly warn the user if one introduces circular dependencies.
Also, I changed the pipe to the build log from
|
to|&
so that both stdout and stderr are written to the build log when${quiet}==false