Can 'make' check if mtime of a dependency is *different* between runs, not just if it's newer than target?

妖精的绣舞 提交于 2019-12-11 00:38:14

问题


If foo_user.cpp depends on foo.h, then foo_user.cpp is built, and then foo.h's modification time is set to further in the past, make will not rebuild foo_user.cpp (because foo.cpp is 'newer'). I'd prefer it if make recorded the modification times of dependencies, and if they changed at all (newer or older), to consider targets of that dependency to be out of date. Can GNU make do this? If not, is there an easy alternative?

In case you're curious how this situation arises: foo.h resides in a symlinked folder. The symlink may point to the foolib-1.0 folder, the foolib-2.0 folder, etc. When the symlink points at a different version of the library, even an older version, foo_user.cpp should be rebuilt. If I simply specifiy symlinkfolder/foo.h as a dependency of foo_user.cpp, make only pays attention to the timestamp of foo.h, not the timestamp of the symlink'd directory through which foo.h is accessed. I can't add the symlink itself as a dependency, because the make rule is generated by the compiler (GCC has a special flag that when given causes it to output a make rule for all the headers a source file depends on).


回答1:


I'm trying to understand why you can't just add the symlink as a dependency. I imagine your automatic dependencies are on one line, but you can have as many as you want.

x.o: a.h b.h    
x.o: c.h    
x.o: d.h

But having said that, it seems likely that make will stat the symlink's target, and not the symlink itself, so that may not DTRT. I suppose you could just touch a file somewhere whenever you make the symlink, but I also suppose you've already thought of that...

You could have a rule that runs ls -id link/. > test, which will put the inode number of the link target directory in test. You could then cmp test save, where save is from the last run. You could then have that make rule do make clean && make target if they are different.

targetwrapper: 
    ls -id link/. > test
    cmp test save || make clean
    make realtarget
    cp test save

clean:
    echo cleaned

realtarget:
    echo made



回答2:


No, Make does not support this. You may wish to consider using another build system such as SCons, which does not rely solely on the timestamp but actually computes the MD5 hash of source files and bases its decisions on the hashes.

From "What makes SCons better?" on its web site:

  • Reliable detection of build changes using MD5 signatures; optional, configurable support for traditional timestamps.



回答3:


While make doesn't support it out of the box, you can program it.

include more_deps

ifneq ($(MAKE_RESTARTS),)

more_deps:
  if (foolink.old differs from what foolink points to) ; then \
    readlink foolink > foolink.old ; \
    echo "foo_user: foolink_trigger" > more_deps ; \
    touch foolink_trigger ; \
  else \
    echo "" > more_deps ;\
  fi

endif

foo_user: foo_user.cpp
  g++ $^ -o $@

Here you include makefile more_deps which sometimes will include the dependency on the symlink's trigger. Trigger is a special intermediate flie, all the meaningful informaion in which is its timestamp. When the symlink changes, the timestamp of the trigger is updated to current time (see touch), thus making foo_user outdated and it is the rebuilt.

include and MAKE_RESTARTS are needed to restart make after calculating the dependency described above. If the makefile being included is a target itself, the target is considered to be rebuilt, is rebuilt and then make restarts and re-reads makefile. But when it reads makefile for the second time, it doesn't see more_deps as a target, because MAKE_RESTARTS variable expands to non-empty string.

In fact, the line with if can sound like this:

more_deps:
  if (any condition you want with $(VARIABLES) possible!) ; then \
     update a file that holds the previous state ;\ 
     ...



回答4:


Through which process do you change the symlink? You could add a make clean type of action to the script that changes the symlink.

You could also set up a "header working folder" in with you let make copy your header files, where the copied header files are dependent on their original and the symlink. The dependencies generated by GCC only take the working headers into account and won't clash with your copy headers into the working folder part of your Makefile.



来源:https://stackoverflow.com/questions/1704003/can-make-check-if-mtime-of-a-dependency-is-different-between-runs-not-just

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!