I use the uptodate? method in Ruby to determine if a file must be re-compiled/re-linked /re-generated etc. Sometimes the build framework I use is so fast at these steps that the output file and the prerequisite file have the exact same file modification timestamps. This causes the build framework to re-compile/re-link files unnecessarily.
I compare timestamps for building like so –
compile_file(file) unless uptodate?(file, %W(#{dependencies}))
I looked up the source for uptodate? from here and it looks like this –
def uptodate?(new, old_list, options = nil)
raise ArgumentError, 'uptodate? does not accept any option' if options
return false unless File.exist?(new)
new_time = File.mtime(new)
old_list.each do |old|
if File.exist?(old)
return false unless new_time > File.mtime(old)
end
end
true
end
As suspected, it returns false if the timestamps are equal. What’s the most elegant way to get around this issue? I have tried running the framework on Linux and Windows and I have the same problem. From what I read here it’s unlikely to be a file system specific file modification time resolution issue (since ext4 has a resolution of 1 microsecond).
uptodate?seems correct. If the timestamps are equal, the file may be up to date, or it may not. Therefore it errs on the safe side and declares it out of date.In the steps where you build files, add logic to advance the time by the built file by a second if it is equal to the time of its dependency. Yes, it’s a hack, but might be the best you can do under the circumstances.
Some file systems (ext4, etc.) can store timestamps with sub-second resolution and might be worth looking at.
Barring any of the above, you can either monkey-patch uptodate? or just create your own that errs on the side of not-building when the timestamps are equal.