Search code examples
makefilegnu-makegnu

How can I build two interactive web-sites from one GNU makefile and mostly the same source?


I'm using GNU Make to build a dynamic web site but I need to build two versions. As a net result currently I run my makefile using two command line incantations. This is inefficient and can result in errors (I don't always remember to run both versions or make a typing error and they fail) thus I want to make it one build.

The Command Line incantations are:

sudo make release build=test
sudo make release build=release

The two incantations activate ifeq blocks that set the path and modify some files. Part of the much simplified (to help readability) top level makefile:

subs = today tomorrow
files = index.php foot.php

ifeq ($(build),test)
export path = /var/www/html/cgi-test
$(shell cp -f head-test.php head.php)
$(shell sed -i '/"DB"/c\  define("DB", "db_test");' subs.php)
else ifeq ($(build),release)
export path = /var/www/html/cgi-new
$(shell cp -f head-release.php head.php)
$(shell sed -i '/"DB"/c\  define("DB", "db_new");' subs.php)
endif

.PHONY: all go       

all:
    $(MAKE) go
    @for ALL in $(subs);\
        do $(MAKE) -C $$ALL all || exit $$?;\
    done;

go:
    cp $(files) $(path)/.

The sub-makefiles have a very similar structure but don't need the ifeq blocks because the files and paths have already been setup.

I think I can simply move the shell commands into the .PHONY rules but I can't do that with the exports because I get errors "export: : bad variable name".

I could do it with a batch file and call the makefile twice but that sidesteps the problem rather than cures it and I wish to learn from the process.

So can anybody show me the way to do this in a makefile?

Thanks to Tripleee here is the answer that finally worked back ported to match my starting post. The one major change is that I have gone back to 'all' as the rule I expect to start the build habits die hard! - Thanks

.PHONY: all both rel-test rel-release

cgi-test := cgi-test
db-test := db_test

cgi-release := cgi-new
db-release := db_new

subs = today tomorrow
files = index.php foot.php

all: both

both: rel-test rel-release

rel-test rel-release: rel-%:
    cp -f head-$*.php head.php
    sed -i '/"DB"/c\  define("DB", "$(db-$*)");' subs.php
    $(MAKE) go path=/var/www/html/strutts/$(cgi-$*)
    @for ALL in $(subs);\
      do $(MAKE) build=$* path=/var/www/html/strutts/$(cgi-$*) -C $$ALL all || exit $$?;\
    done;

Solution

  • Something like this?

    .PHONY: both rel-test rel-release
    both: rel-test rel-release
    
    cgi-test := cgi-test
    db-test := db_test
    
    cgi-release := cgi-new
    db-release := db_new
    
    rel-%:
        cp -f head-$*.php head.php
        sed -i '/"DB"/c\    define("DB", "$(db-$*)")' subs.php
        $(MAKE) release build=$* path=/var/www/html/$(cgi-$*)
    

    The reason the export can't be moved into a recipe is that you are using the export command of make itself, not the shell's command with the same name.

    You absolutely should not use sudo unless you specifically require the output files to be owned and only writable by root. Even then, running as much as possible as a regular user would be proper hygiene; maybe add a sudo command inside the Makefile to copy the files to their final location.