Message ID | 20170914184540.26650-1-uwe@kleine-koenig.org (mailing list archive) |
---|---|
State | Rejected, archived |
Headers | show |
On Thu, Sep 14, 2017 at 2:45 PM, Uwe Kleine-König <uwe@kleine-koenig.org> wrote: > This way version.h isn't generated when running $(make clean) but only > when lib.c is about to be compiled. > > This simplifies packaging for Debian because the package building programs > abort when there are additional files after $(make clean). BTW, this one needs a SOB as well. I want to apply the modify 3 liner version using the $(MAKECMDGOALS). Thanks Chris -- To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 09/15/2017 06:52 PM, Christopher Li wrote: > On Thu, Sep 14, 2017 at 2:45 PM, Uwe Kleine-König <uwe@kleine-koenig.org> wrote: >> >> -# Generating file version.h if current version has changed >> SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)') >> -VERSION_H := $(shell cat version.h 2>/dev/null) >> -ifneq ($(lastword $(VERSION_H)),"$(SPARSE_VERSION)") >> -$(info $(shell echo ' GEN 'version.h)) >> -$(shell echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h) >> -endif > > You don't need to move them to into a rule section. > > You can use "ifneq ($(MAKECMDGOALS),clean)" So it still triggers when doing make clean all Also you don't want to generate it for $(make check). IMHO that's hardly manageable to get done consistently this way and the easiest is a separate rule for version.h that is triggered by make dependencies as I suggested > to wrap it. GNU make document even show that as examples > of using $(MAKECMDGOALS). IMHO that is no prove that the idea is sane. >> +version.h: FORCE >> + $(QUIET_GEN)echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h.tmp; \ >> + if cmp -s version.h version.h.tmp; then \ >> + rm version.h.tmp; \ >> + else \ >> + mv version.h.tmp version.h; \ >> + fi >> + >> +.PHONY: FORCE >> + >> +lib.o: version.h >> + > > The above section is not needed if you use the ifneq test on $(MAKECMDGOALS).> I also test it and found the problem that, the version.h was force > to obsolete. Two consequent make will always show "GEN version.h" > line. Then maybe split it into CHECK version.h GEN version.h ? The GEN would be skipped if version.h doesn't need an update. Best regards Uwe
On Tue, Sep 19, 2017 at 10:50 AM, Uwe Kleine-König <uwe@kleine-koenig.org> wrote: >> You can use "ifneq ($(MAKECMDGOALS),clean)" > > So it still triggers when doing > > make clean all That is the correct behavior. Because "all" require version.h. It is a silly thing to put clean and all together, but the makefile actually do the right thing. > > Also you don't want to generate it for $(make check). check is depend on all which depend on version.h. So that seems acceptable to me. Plus in the make check case, it will only look at the version.h, it will not regenerate it if data is the same. > IMHO that's hardly manageable to get done consistently this way and the > easiest is a separate rule for version.h that is triggered by make > dependencies as I suggested The problem is that, you end up updating the version.h from make's point of view. Then make detect the version.h's time stamp haven't change and take a short cut. That is the part I consider not clean. In other words, if you only look at the make rules and ignore the time stamp short cut. "version.h" will be force to update every time. It should also recompile lib.o without the short cut. >> to wrap it. GNU make document even show that as examples >> of using $(MAKECMDGOALS). > > IMHO that is no prove that the idea is sane. All the example you give seems give sane result. >> The above section is not needed if you use the ifneq test on $(MAKECMDGOALS).> I also test it and found the problem that, the version.h was force >> to obsolete. Two consequent make will always show "GEN version.h" >> line. > > Then maybe split it into > > CHECK version.h > GEN version.h > > ? The GEN would be skipped if version.h doesn't need an update. Then there is another thing I consider slightly unclean. The check rules will optionally update another target "version.h" without specificity in its rules. We can use order only rules for check target. The whole thing seems gets more complicated than it needs to. Chris -- To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Sep 19, 2017 at 11:42:30AM -0400, Christopher Li wrote: > On Tue, Sep 19, 2017 at 10:50 AM, Uwe Kleine-König > <uwe@kleine-koenig.org> wrote: > >> You can use "ifneq ($(MAKECMDGOALS),clean)" > > > > So it still triggers when doing > > > > make clean all > > That is the correct behavior. Because "all" require version.h. After just adding version.h to clean (which might be a sensible separate change?) but without your proposed change I get this: uwe@taurus:~/sparse$ make clean all find validation/ \( -name "*.c.output.expected" \ -o -name "*.c.output.got" \ -o -name "*.c.output.diff" \ -o -name "*.c.error.expected" \ -o -name "*.c.error.got" \ -o -name "*.c.error.diff" \ \) -exec rm {} \; rm -f *.[oa] .*.d *.so test-lexing test-parsing obfuscate compile graph sparse test-linearize example test-unssa test-dissect ctags c2xml test-inspect sparse-llvm libsparse.so pre-process.h sparse.pc version.h CC test-lexing.o CC target.o CC parse.o CC tokenize.o CC pre-process.o CC symbol.o CC lib.o lib.c:46:10: fatal error: version.h: No such file or directory #include "version.h" ^~~~~~~~~~~ compilation terminated. Makefile:212: recipe for target 'lib.o' failed make: *** [lib.o] Error 1 I'd say this is not correct behaviour. The problem is that as is done now, version.h is created while make parses the Makefile and doesn't really know about the dependencies (yet). As a consequence make doesn't notice that version.h is missing while compiling lib.c. So here are needlessly two things mixed: parsing the Makefile and generating version.h. It all gets easier if Makefile is parsed first without caring about version.h as something special and then treat the header just like every other target. > It is a silly thing to put clean and all together, but the makefile > actually do the right thing. I'd say it's subjective if you consider that silly or not. I usually do this if I don't trust the build system (e.g. because the build system contains strange constructs involving MAKECMDGOALS :-) > > Also you don't want to generate it for $(make check). > > check is depend on all which depend on version.h. > So that seems acceptable to me. ok > Plus in the make check case, it will only look at the version.h, > it will not regenerate it if data is the same. That's shared with my approach. > > IMHO that's hardly manageable to get done consistently this way and the > > easiest is a separate rule for version.h that is triggered by make > > dependencies as I suggested > > The problem is that, you end up updating the version.h from make's > point of view. Then make detect the version.h's time stamp haven't > change and take a short cut. That is the part I consider not clean. I cannot follow here. lib.c depends on version.h and always when you update version.h you want to recompile lib.c, don't you? Checking timestamps is what make is good at (and there for), so I don't understand your concern. And conditionally updating a target to keep the old file if no update is needed is a usual approach. > In other words, if you only look at the make rules and ignore the > time stamp short cut. "version.h" will be force to update every > time. It should also recompile lib.o without the short cut. I'd not call it "time stamp short cut" but version.h being a target that is only updated when necessary. Looks like plain make for me. Another "problem" with the current approach is that version.h is generated synchronously and so it is not parallelized as it should. (IMHO doesn't matter much because build time is short enough, but IMHO still a good hint that the construct is broken.) > >> to wrap it. GNU make document even show that as examples > >> of using $(MAKECMDGOALS). > > > > IMHO that is no prove that the idea is sane. > > All the example you give seems give sane result. Do you still think that after the failure reported above? > >> The above section is not needed if you use the ifneq test on $(MAKECMDGOALS).> I also test it and found the problem that, the version.h was force > >> to obsolete. Two consequent make will always show "GEN version.h" > >> line. > > > > Then maybe split it into > > > > CHECK version.h > > GEN version.h > > > > ? The GEN would be skipped if version.h doesn't need an update. > > Then there is another thing I consider slightly unclean. > The check rules will optionally update another target "version.h" without > specificity in its rules. I don't understand that. > We can use order only rules for check target. The whole thing seems > gets more complicated than it needs to. I don't follow. Best regards Uwe
On Tue, Sep 19, 2017 at 2:19 PM, Uwe Kleine-König <uwe@kleine-koenig.org> wrote: > CC pre-process.o > CC symbol.o > CC lib.o > lib.c:46:10: fatal error: version.h: No such file or directory > #include "version.h" > ^~~~~~~~~~~ > compilation terminated. > Makefile:212: recipe for target 'lib.o' failed > make: *** [lib.o] Error 1 > > I'd say this is not correct behaviour. The problem is that as is done now, > version.h is created while make parses the Makefile and doesn't really > know about the dependencies (yet). As a consequence make doesn't notice > that version.h is missing while compiling lib.c. No, that is not what is happening. What is happen is that, your "make clean all" is incorrect command in the sense that, "clean" and "all" does not have dependency and order between them. So it is just a race condition which get to run first in the parallel build environment. In your case, there is only one job. Clean runs first. But if there is more than one job, even you specify the lib.o depend on version.h. It is still not safe. It can happen in the order of: 1) job1 "create version.h", 2) job2 "clean" remove version.h 3) job1 compile lib.o -> missing version.h The root of the evil is that, your "make clean all" does not make sense. It does not specify order between "clean" vs "all". make can invoke it whichever order it see fit. You get it working it is just because you are on the lucky path. > So here are needlessly two things mixed: parsing the Makefile and > generating version.h. It all gets easier if Makefile is parsed first > without caring about version.h as something special and then treat the > header just like every other target. You should not mix clean with other target. Period. Try to support that create a lot of complexity and corner cases. >> Plus in the make check case, it will only look at the version.h, >> it will not regenerate it if data is the same. > > That's shared with my approach. it is slightly different in the sense that, the checking is all done in GNU make function instead of invoking external shell. Granted, we can use $(file ) function to remove the $(sell cat ) part. It is slightly harder to do that inside the rule section. Your patch will always update the version.h and force it to run the command section. Which has a few shell commands. > > I cannot follow here. lib.c depends on version.h and always when you > update version.h you want to recompile lib.c, don't you? Checking Yes, of course. > timestamps is what make is good at (and there for), so I don't > understand your concern. And conditionally updating a target to keep the > old file if no update is needed is a usual approach. As I said, you need to use order only prerequisites to do it properly. Otherwise it is kind of conflicting view version.h is updated or not. From the rules point of view, the version.h is updated, the command section gets executed. From the time stamp point of view, it is not. > > Another "problem" with the current approach is that version.h is > generated synchronously and so it is not parallelized as it should. > (IMHO doesn't matter much because build time is short enough, but IMHO > still a good hint that the construct is broken.) That is not a problem at all. I consider version.h at the bottom of the dependency chain, so there is no paralleled when every body depend on it. The most common case, the version.h does not need to get updated. > > Do you still think that after the failure reported above? I think that failure is "user error". Should not try to mix "clean" with other targets. Nothing good can come out of it. >> Then there is another thing I consider slightly unclean. >> The check rules will optionally update another target "version.h" without >> specificity in its rules. > > I don't understand that. > >> We can use order only rules for check target. The whole thing seems >> gets more complicated than it needs to. The conflicting view is version.h gets updated or not. I think the cleaner way to do it is some thing like: check_version: <update version.h only if needed> version.h: | check_version Because I don't plan to support mixing clean vs other targets. I think using $(MAKECMDGOALS) is simpler and faster, no need to execute external shells for the common case. Chris -- To unsubscribe from this list: send the line "unsubscribe linux-sparse" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Makefile b/Makefile index a4653aa1b747..13b0f97f146e 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,6 @@ VERSION=0.5.1 -# Generating file version.h if current version has changed SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)') -VERSION_H := $(shell cat version.h 2>/dev/null) -ifneq ($(lastword $(VERSION_H)),"$(SPARSE_VERSION)") -$(info $(shell echo ' GEN 'version.h)) -$(shell echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h) -endif OS = linux @@ -215,6 +209,18 @@ pre-process.sc: CHECKER_FLAGS += -Wno-vla %.o: %.c $(LIB_H) $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< +version.h: FORCE + $(QUIET_GEN)echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h.tmp; \ + if cmp -s version.h version.h.tmp; then \ + rm version.h.tmp; \ + else \ + mv version.h.tmp version.h; \ + fi + +.PHONY: FORCE + +lib.o: version.h + %.sc: %.c sparse $(QUIET_CHECK) $(CHECKER) $(CHECKER_FLAGS) -c $(ALL_CFLAGS) $< @@ -223,7 +229,7 @@ selfcheck: $(ALL_OBJS:.o=.sc) clean: clean-check - rm -f *.[oa] .*.d *.so $(PROGRAMS) $(SLIB_FILE) pre-process.h sparse.pc + rm -f *.[oa] .*.d *.so $(PROGRAMS) $(SLIB_FILE) pre-process.h sparse.pc version.h dist: @if test "$(SPARSE_VERSION)" != "v$(VERSION)" ; then \