开发者

How do I use dependencies in a makefile without calling a target?

I'm using makefiles to convert an internal file format to an XML file which is sent to other colleagues. They would make changes to the XML file and send it back to us (Don't ask, this needs to be this way ;)). I'd like to use my makefile to update the internal files when this XML changes.

So I have these rules:

%.internal: $(DATAFILES)
       # Read changes from XML if any
       # Create internal representation here

%.xml: %.internal
       # Convert to XML here

Now th开发者_JAVA百科e XML could change because of the workflow described above. But since no data files have changed, make would tell me that file.internal is up-to-date. I would like to avoid making %.internal target phony and a circular dependency on %.xml obviously doesn't work.

Any other way I could force make to check for changes in the XML file and re-build %.internal?


You want to allow two different actions: making the xml file from the internal file, and making the internal file from the xml file. Since Make knows only the modification times, it knows which target is older but not whether it should be remade. So put in another file as a flag to record when either action was last taken, and make that your primary target; if either target is newer than the flag, it has been modified by something other than these actions, and make should rebuild the older target (and then touch the flag).

There are several ways to implement this. In some versions of Make (such as recent versions of GNUMake) you can write double-colon rules, so that Make will rebuild a target differently, based on which preq triggered it:

%.flag:: %.internal
    # convert $*.internal to $*.xml
    touch $@

%.flag:: %.xml
    # rewrite $*.internal based on $*.xml
    touch $@

A less elegant but more portable way is to look at $? and rebuild the other file:

%.flag: %.xml %.internal
ifeq ($?,$*.internal)
    # convert $*.internal to $*.xml
else
    # rewrite $*.internal based on $*.xml
endif
    touch $@


I think you could do something like this:

all: .last-converted-xml .last-converted-internal

.last-converted-internal: *.internal
    ./internal-2-xml $?
    touch $@ .last-converted-xml

.last-converted-xml: *.xml
    ./xml-2-internal $?
    touch $@ .last-converted-internal

This runs "xml-convert" on any .xml files newer than an arbitrary marker file, ".last-converted". The $? should give you a list of all dependencies (*.xml) that are newer than the marker file.

Of course, the xml-convert program will have to be written to take a list of xml files and process each one.

I'm not sure from the question whether you actually need the .internal file, or if that was just an attempt to get the makefile working. So, either your "xml-convert" program can convert each .xml file in place, or it can also generate file.internal as well if you need it.


Use the -W option of make to have make think one of the data files has changed:

make -W somedatafile

This will cause make to think somedatafile has been modified without actually changing it's modification time.


Would it be possible to use different names for the XML file? The file you create from the internal format would have one name and the file your colleagues send you another? If they used different names there would be no circular dependency.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜