Friday, October 28, 2022

[SOLVED] How would I create a Makefile that remotely updates itself?

Issue

I have a makefile that I've changed up a bit here to look more generalized

.PHONY:
        bash hash.sh

all: .PHONY lab tests.zip

lab: .PHONY lab.cpp
        g++ -o lab lab.cpp -g -Wall -std=c++11

tests.zip:
        curl -L -O https://url/tests.zip
        unzip tests.zip

tests: .PHONY lab tests.zip
        bash scripts/test.bash lab.cpp

clean:
        rm -rf scripts tests bitset-tests.zip

I am a TA for an entry level computer science course at my university, and I've created a makefile here for my students to use to compile and test their code seamlessly.

One thing I want to do though is to have the makefile update itself every time the remote repository has a new version of it. I know I could just have them update the file themselves, but my job is to make the students focus less on setting things up and more on just coding for now, since it's entry level. So for the purposes of this, I'm sticking with the idea I have.

Currently, I'm achieving this with a script hash.sh which fetches a hash of the makefile from the repo, and compares it to a hash of the makefile in the student's directory. If the hashes don't match, then the updated makefile is fetched and replaces the old one. This is done in the .PHONY recipe. I should also mention that I don't want to add a recipe that updates it like make update, because again I want the process to be seamless. You'd be surprised how many students wouldn't utilize that feature, so I want to build it into the ones they will use for sure.

Is there a better method for this, or am I doing something wrong with this one?


Solution

Thomas has the right idea, but you can't use .PHONY here because it would means the makefile is ALWAYS out of date; make knows this so it doesn't re-exec itself if its included makefile is marked .PHONY.

You need to create a way for make to know if the makefile was changed since the last time it was run locally. I recommend you do it like this:

<normal makefile here>

Makefile: FORCE
        curl https://.../Makefile -o Makefile.tmp
        cmp -s Makefile Makefile.tmp && rm -f Makefile.tmp || mv -f Makefile.tmp Makefile

FORCE:

What does this do? First it uses a FORCE target which is an old-school way to emulate a .PHONY target, which is always out of date, without actually using .PHONY (which as I mentioned above, is handled specially by GNU make in this situation).

Second it retrieves the Makefile but only updates the local makefile if it has changed. If it hasn't changed, it doesn't update the local makefile and so make won't re-exec itself.



Answered By - MadScientist
Answer Checked By - Cary Denson (WPSolving Admin)