# make.configuration.deps file for thorn Formaline -*-Makefile-*- # Some configury magic # Should we use gtar or tar? TAR := $(shell gtar --help > /dev/null 2> /dev/null && echo gtar || echo tar) # Does tr support -C, or should we use -c instead? TR_C := $(shell tr -C 'a' 'b' < /dev/null > /dev/null 2> /dev/null && echo 'tr -C' || echo 'tr -c') ################################################################################ # Create a tarball of the source code whenever this thorn is linked # into an executable TARBALL_DIR = $(SCRATCH_BUILD) #CACTUSLIBLINKLINE += $(CCTK_LIBDIR)/$(LIBNAME_PREFIX)$(CCTK_LIBNAME_PREFIX)Formaline-cactus-source$(LIBNAME_SUFFIX) CACTUSLIBLINKLINE += -l$(CCTK_LIBNAME_PREFIX)Formaline-cactus-source FRM-LIB = $(CCTK_LIBDIR)/$(LIBNAME_PREFIX)$(CCTK_LIBNAME_PREFIX)Formaline-cactus-source$(LIBNAME_SUFFIX) $(EXEDIR)$(DIRSEP)$(EXE): $(FRM-LIB) FRM-OBJS = $(TARBALL_DIR)/cactus-meta-source.o $(TARBALL_DIR)/build-id.o $(TARBALL_DIR)/cactus-flesh-source.o $(patsubst %,$(TARBALL_DIR)/cactus-thorn-source-%.o,$(notdir $(THORNS))) $(FRM-LIB): $(FRM-OBJS) # $(AR) $(ARFLAGS) $@ $^ $(MAKE) -f $(MAKE_DIR)/make.configuration $(FRM-LIB).objectlist.custom xargs -n $(FRM-OBJS-words-max) $(AR) $(ARFLAGS) $@ < $(FRM-LIB).objectlist $(RM) $(FRM-LIB).objectlist if test "x$(USE_RANLIB)" = "xyes" ; then $(RANLIB) $(RANLIBFLAGS) $@ ; fi @echo $(DIVIDER) .PRECIOUS: $(FRM-LIB) ## Cache optimisation: ## Build the thorns' tarballs already while the thorns are compiled ## (does not work) # #$(CCTK_LIBDIR)/$(LIBNAME_PREFIX)$(CCTK_LIBNAME_PREFIX)%$(LIBNAME_SUFFIX): $(TARBALL_DIR)/cactus-thorn-source-%.o # Unique ID for the build # (force a new ID to be created every time) # (do this after the thorn's library has been built, so that the # script gethostname.pl has been copied to the scratch directory) # (generates also $(TOP)/CONFIG-ID) .PRECIOUS: $(TOP)/BUILD-ID .PHONY: $(TOP)/BUILD-ID $(TOP)/BUILD-ID: $(CCTK_LIBDIR)/$(LIBNAME_PREFIX)$(CCTK_LIBNAME_PREFIX)Formaline$(LIBNAME_SUFFIX) config=`echo "$(EXE:cactus_%=%)" | $(TR_C) -d '[:alnum:]+-._]'` && \ hostname=`$(TARBALL_DIR)/gethostname.pl` && \ user="$$USER" && \ dirname=`echo "$(subst /,-,$(CCTK_HOME:/%=%))" | $(TR_C) -d '[:alnum:]+-._]'` && \ timestamp=`date -u +%Y.%m.%d-%H.%M.%S` && \ pid="$$$$" && \ build_id="build-$$config-$$hostname-$$user-$$timestamp-$$pid" && \ echo "$$build_id" > $@ && \ config_id="config-$$config-$$hostname-$$dirname" && \ echo "$$config_id" > $(TOP)/CONFIG-ID .PRECIOUS: $(TARBALL_DIR)/build-id.o $(TARBALL_DIR)/build-id.o: $(TARBALL_DIR)/build-id.c $(CC) $(CFLAGS) -c -o $@ $^ .PRECIOUS: $(TARBALL_DIR)/build-id.c $(TARBALL_DIR)/build-id.c: $(TOP)/BUILD-ID { \ echo '/* This is an auto-generated file -- do not edit */' && \ build_id="$$(cat $(TOP)/BUILD-ID)" && \ echo 'char const * const build_id = "'$$build_id'";' && \ config_id="$$(cat $(TOP)/CONFIG-ID || echo 'NO-CONFIG-ID')" && \ echo 'char const * const config_id = "'$$config_id'";'; \ } > $@ # Meta information $(TARBALL_DIR)/cactus-meta-source.o: $(TARBALL_DIR)/cactus-meta-source.c $(CC) $(CFLAGS) -c -o $@ $^ $(TARBALL_DIR)/cactus-meta-source.c: $(TARBALL_DIR)/cactus-flesh-source.c $(patsubst %,$(TARBALL_DIR)/cactus-thorn-source-%.c,$(notdir $(THORNS))) $(TARBALL_DIR)/makemetablob.pl Cactus $(notdir $(THORNS)) > $@ .PRECIOUS: $(TARBALL_DIR)/cactus-meta-source.c $(TARBALL_DIR)/cactus-meta-source.o #cleandeps: # rm -rf $(TOP)/scratch/cactus-flesh-source.files $(TOP)/scratch/cactus-flesh-source.ccldeps $(TOP)/scratch/cactus-thorn-source-*.files $(TOP)/scratch/cactus-thorn-source-*.ccldeps ############################################################################### # Flesh ############################################################################### $(TARBALL_DIR)/cactus-flesh-source.o: $(TARBALL_DIR)/cactus-flesh-source.c @echo "Creating Formaline tarball for the flesh" $(CC) $(CFLAGS) -c -o $@ $^ $(TARBALL_DIR)/cactus-flesh-source.c: $(TARBALL_DIR)/cactus-flesh-source.tar.gz $(CCTK_HOME)/arrangements/AEIThorns/Formaline/src/util/VERSION $(TARBALL_DIR)/makeblob.pl '' Cactus < $< > $@ $(TARBALL_DIR)/cactus-flesh-source.tar.gz: $(TARBALL_DIR)/cactus-flesh-source.files cd $(CCTK_HOME) && \ $(TAR) czf $@ -T $< # This dependency means that the tarball for a thorn is only updated # if the thorn is actually recompiled. This does not catch changes to # files that do not influence the executable. $(TARBALL_DIR)/cactus-flesh-source.files: $(CCTK_LIBDIR)/$(LIBNAME_PREFIX)$(CCTK_LIBNAME_PREFIX)$(FLESHLIB)$(LIBNAME_SUFFIX) $(TARBALL_DIR)/cactus-flesh-source.ccldeps cd $(CCTK_HOME) && \ find CONTRIBUTORS COPYRIGHT Makefile lib src \ `ls configs/$(notdir $(TOP))/OptionList 2> /dev/null` \ `ls configs/$(notdir $(TOP))/ScriptFile 2> /dev/null` \ configs/$(notdir $(TOP))/ThornList \ configs/$(notdir $(TOP))/config-data \ configs/$(notdir $(TOP))/config-info \ -name 'CVS' -prune -o \ -name '.*' -prune -o \ -name '*~' -prune -o \ ! -type d \ -print > $@ -include $(TARBALL_DIR)/cactus-flesh-source.ccldeps # Make aborts if these dependencies vanish. Therefore mention only files # here that cannot go away. $(TARBALL_DIR)/cactus-flesh-source.ccldeps: { \ echo "$(@:%.ccldeps=%.files) \\"; \ echo "$@: \\"; \ echo " $(CCTK_HOME)/src/interface.ccl \\"; \ echo " $(CCTK_HOME)/src/param.ccl \\"; \ echo " $(CCTK_HOME)/src/schedule.ccl"; \ } > $@ .PRECIOUS: $(TARBALL_DIR)/cactus-flesh-source.ccldeps $(TARBALL_DIR)/cactus-flesh-source.files $(TARBALL_DIR)/cactus-flesh-source.tar.gz $(TARBALL_DIR)/cactus-flesh-source.c $(TARBALL_DIR)/cactus-flesh-source.o ############################################################################### # Thorns ############################################################################### $(TARBALL_DIR)/cactus-thorn-source-%.o: $(TARBALL_DIR)/cactus-thorn-source-%.c @echo "Creating Formaline tarball for thorn $*" $(CC) $(CFLAGS) -c -o $@ $^ $(TARBALL_DIR)/cactus-thorn-source-%.c: $(TARBALL_DIR)/cactus-thorn-source-%.tar.gz $(CCTK_HOME)/arrangements/AEIThorns/Formaline/src/util/VERSION $(TARBALL_DIR)/makeblob.pl $(patsubst %/,%,$(dir $(filter %/$(@:$(TARBALL_DIR)/cactus-thorn-source-%.c=%),$(THORNS)))) $(@:$(TARBALL_DIR)/cactus-thorn-source-%.c=%) < $< > $@ $(TARBALL_DIR)/cactus-thorn-source-%.tar.gz: $(TARBALL_DIR)/cactus-thorn-source-%.files cd $(CCTK_HOME) && \ $(TAR) czf $@ -T $< # This dependency means that the tarball for a thorn is only updated # if the thorn is actually recompiled. This does not catch changes to # files that do not influence the executable. $(TARBALL_DIR)/cactus-thorn-source-%.files: $(CCTK_LIBDIR)/$(LIBNAME_PREFIX)$(CCTK_LIBNAME_PREFIX)%$(LIBNAME_SUFFIX) $(TARBALL_DIR)/cactus-thorn-source-%.ccldeps cd $(CCTK_HOME) && \ find arrangements/$(filter %/$*,$(THORNS))/. \ -name 'doc' -prune -o \ -name 'par' -prune -o \ -name 'test' -prune -o \ -name 'CVS' -prune -o \ -name '.*' -prune -o \ -name '*~' -prune -o \ ! -type d \ -print > $@ -include $(patsubst %,$(TARBALL_DIR)/cactus-thorn-source-%.ccldeps,$(notdir $(THORNS))) # Make aborts if these dependencies vanish. Therefore mention only files # here that cannot go away. $(TARBALL_DIR)/cactus-thorn-source-%.ccldeps: { \ echo "$(@:%.ccldeps=%.files) \\"; \ echo "$@: \\"; \ echo " $(CCTK_HOME)/arrangements/$(filter %/$*,$(THORNS))/interface.ccl \\"; \ echo " $(CCTK_HOME)/arrangements/$(filter %/$*,$(THORNS))/param.ccl \\"; \ echo " $(CCTK_HOME)/arrangements/$(filter %/$*,$(THORNS))/schedule.ccl"; \ } > $@ .PRECIOUS: $(TARBALL_DIR)/cactus-thorn-source-%.ccldeps $(TARBALL_DIR)/cactus-thorn-source-%.files $(TARBALL_DIR)/cactus-thorn-source-%.tar.gz $(TARBALL_DIR)/cactus-thorn-source-%.c $(TARBALL_DIR)/cactus-thorn-source-%.o ############################################################################### # Helpers ############################################################################### # Create a file containing the names of all object files. # Since the list may be too long to be passed to a shell, it is split # into a set of rules which add lines to a file. This file can later # be used via xargs. FRM-OBJS-words = $(words $(FRM-OBJS)) ifeq ($(shell uname),AIX) # Be conservative about the maximum number of objects that can be # handled at once. AIX has a command line length limit of about # 32000. Each object's path name may be about 200 characters long. FRM-OBJS-words-max = 100 else # Assume that the system has no limit to speak of. FRM-OBJS-words-max = 10000 endif ifeq ($(shell test $(FRM-OBJS-words) -le $(FRM-OBJS-words-max) && echo 1), 1) # The list is short. Create the file directly, which is faster. .PHONY: $(FRM-LIB).objectlist.custom $(FRM-LIB).objectlist.custom: echo $(FRM-OBJS) > $(FRM-LIB).objectlist else # The list is long. Create the file via a set of rules, one rule per # object file. FRM-OBJS-added = $(FRM-OBJS:%=%.added) .PHONY: $(FRM-LIB).objectlist.custom $(FRM-LIB).objectlist.custom: $(FRM-OBJS-added) # Truncate the file .PHONY: $(FRM-LIB).objectlist.create $(FRM-LIB).objectlist.create: : > $(FRM-LIB).objectlist # Add a line to the file .PHONY: $(FRM-OBJS-added) $(FRM-OBJS-added): $(FRM-LIB).objectlist.create echo $(@:%.added=%) >> $(FRM-LIB).objectlist endif ############################################################################### # Git repository of source code ############################################################################### # Suppress all output from git commands GIT-SILENT = > /dev/null 2>&1 # Does git exist, or should we do nothing instead? GIT-CMD := $(shell env PATH=$$PATH:$$HOME/git/bin which git) HAVE-GIT := $(shell '$(GIT-CMD)' --version > /dev/null 2>&1 && echo 'true' || echo 'false') GIT1 := $(shell $(HAVE-GIT) && echo '$(SCRATCH_BUILD)/git-lock.pl $(GIT-CMD)' || { echo 'WARNING: git command not found' >&2 && echo 'true'; }) GIT := $(shell $(HAVE-GIT) && echo '$(SCRATCH_BUILD)/git-lock.pl $(GIT-CMD) $(GIT-SILENT)' || { echo 'WARNING: git command not found' >&2 && echo 'true'; }) ifeq ($(HAVE-GIT),true) main: git-store-source .PHONY: git-store-source git-store-source: git-commit-everything git-push-everything echo "Formaline: Done." GIT-ROOT = $(CCTK_HOME) GIT-REPO = $(TOP)/configjar.git GIT-MASTER-REPO = $(CCTK_HOME)/cactusjar.git GIT-THORNS = $(notdir $(THORNS)) BUILD-ID-FILE = $(TOP)/BUILD-ID CONFIG-ID-FILE = $(TOP)/CONFIG-ID define GIT-INIT-MASTER-REPO { \ if [ ! -e $(GIT-MASTER-REPO)/.git/HEAD ]; then \ echo "Formaline: Creating master git repository..." && \ mkdir -p $(GIT-MASTER-REPO) && \ cd $(GIT-MASTER-REPO) && \ $(GIT) init-db; \ fi && \ if [ ! -e $(GIT-MASTER-REPO)/README ]; then \ { \ echo "This directory $$(pwd)" && \ echo "is not empty -- it contains a git repository with the Cactus source" && \ echo "trees of all previous builds, starting on $$(date)." && \ echo "" && \ echo "You can use the command \"git branch\" to list all configurations that" && \ echo "are stored in this repository. The history of each branch is the" && \ echo "sequence in which the configuration was built. The most recent build" && \ echo "is stored in the branch head, as usual. In order to check out a" && \ echo "certain branch into a directory , issue the following commands:" && \ echo " cd " && \ echo " mkdir " && \ echo " cd " && \ echo " git init" && \ echo " git pull $$(pwd) " && \ echo "" && \ echo "You can also use the command \"git tag -l\" to list all builds that are" && \ echo "stored in this repository. This keeps the source tree for each build" && \ echo "directly accessible. In order to check out a certain tag into a" && \ echo "directory , issue the following commands:" && \ echo " cd " && \ echo " git clone -o $$(pwd)" && \ echo " git checkout "; \ } > $(GIT-MASTER-REPO)/README; \ fi; \ } || echo "WARNING: Error while handling git repository" endef define GIT-INIT-REPO { \ if [ ! -e $(GIT-REPO)/.git/HEAD ]; then \ echo "Formaline: Creating git repository..." && \ mkdir -p $(GIT-REPO) && \ cd $(GIT-REPO) && \ $(GIT) init-db; \ fi; \ } || echo "WARNING: Error while handling git repository" endef # Call git-gc if the repository has grown in size by more than a # factor of 10. This macro needs to be called in the directory where # the .git subdirectory lives. define GIT-COMPACT-REPO { \ if [ ! -e .oldreposize ]; then \ echo 0 > .oldreposize; \ fi && \ oldreposize=$$(cat .oldreposize) && \ maxreposize=$$((oldreposize * 10)) && \ reposize=$$(du -s .git | awk '{ print $$1; }') && \ if [ $$reposize -gt $$maxreposize ]; then \ $(GIT) gc && \ reposize=$$(du -s .git | awk '{ print $$1; }') && \ echo $$reposize > .oldreposize; \ fi; \ } || echo "WARNING: Error while handling git repository" endef .PHONY: git-push-everything git-push-everything: git-commit-everything $(BUILD-ID-FILE) $(GIT-INIT-MASTER-REPO) { \ echo "Formaline: Pushing source tree to master git repository..." && \ cd $(GIT-ROOT) && \ export GIT_DIR=$(GIT-REPO)/.git && \ build_id=$$(cat $(BUILD-ID-FILE)) && \ $(GIT) push -f $(GIT-MASTER-REPO) "$$build_id" && \ config_id=$$(cat $(CONFIG-ID-FILE)) && \ $(GIT) push -f $(GIT-MASTER-REPO) "$$config_id"; \ } || echo "WARNING: Error while handling git repository" true || { \ cd $(GIT-ROOT) && \ export GIT_DIR=$(GIT-MASTER-REPO)/.git && \ echo "Formaline: Optimising master git repository..." && \ $(GIT) gc; \ } || echo "WARNING: Error while handling git repository" { \ cd $(GIT-ROOT) && \ export GIT_DIR=$(GIT-MASTER-REPO)/.git && \ echo "Formaline: Optimising master git repository..." && \ cd $(GIT-MASTER-REPO) && \ $(GIT-COMPACT-REPO); \ } || echo "WARNING: Error while handling git repository" { \ if [ -e "$(CCTK_HOME)/cactus.config" ]; then \ source "$(CCTK_HOME)/cactus.config"; \ fi && \ if [ -n "$$CACTUS_CENTRAL_GIT_REPO" ]; then \ cd $(GIT-ROOT) && \ export GIT_DIR=$(GIT-MASTER-REPO)/.git && \ echo "Formaline: Pushing to central repository $$CACTUS_CENTRAL_GIT_REPO..." && \ config_id=$$(cat $(CONFIG-ID-FILE)) && \ { $(GIT1) tag -l && echo "$$config_id"; } | \ xargs $(GIT) push -f "$$CACTUS_CENTRAL_GIT_REPO"; \ fi; \ } || echo "WARNING: Error while handling git repository" # Try to use the previous commit as parent, if possible .PHONY: git-commit-everything git-commit-everything: $(SCRATCH_BUILD)/cactus-flesh-source.git-tag $(GIT-THORNS:%=$(SCRATCH_BUILD)/cactus-thorn-%.git-tag) $(BUILD-ID-FILE) { \ echo "Formaline: Committing source tree to git repository..." && \ cd $(GIT-ROOT) && \ export GIT_DIR=$(GIT-REPO)/.git && \ build_id="$$(cat $(BUILD-ID-FILE))" && \ { $(GIT) commit -m "$$build_id" || true; } && \ $(GIT) tag -f "$$build_id" && \ echo "Formaline: Created git tag $$build_id" && \ config_id="$$(cat $(CONFIG-ID-FILE))" && \ $(GIT) branch -f "$$config_id" && \ echo "Formaline: Updated git branch $$config_id" && \ echo "Formaline: Optimising git repository (slow only the first time)..." && \ true || $(GIT) gc; \ cd $(GIT-REPO) && \ $(GIT-COMPACT-REPO); \ } || echo "WARNING: Error while handling git repository" .PRECIOUS: $(SCRATCH_BUILD)/cactus-flesh-source.git-tag $(SCRATCH_BUILD)/cactus-flesh-source.git-tag: $(TARBALL_DIR)/cactus-flesh-source.files $(GIT-INIT-REPO) { \ echo "Formaline: Adding flesh to git repository..." && \ cd $(GIT-ROOT) && \ export GIT_DIR=$(GIT-REPO)/.git && \ { $(GIT) rm --cached -r CONTRIBUTORS COPYRIGHT Makefile lib src configs > /dev/null 2>&1 || true; } && \ xargs ls < $(TARBALL_DIR)/cactus-flesh-source.files \ > $(TARBALL_DIR)/cactus-flesh-source.files2 2> /dev/null; \ xargs $(GIT) add < $(TARBALL_DIR)/cactus-flesh-source.files2 && \ rm $(TARBALL_DIR)/cactus-flesh-source.files2 && \ : > $@; \ } || echo "WARNING: Error while handling git repository" .PRECIOUS: $(SCRATCH_BUILD)/cactus-thorn-%.git-tag $(SCRATCH_BUILD)/cactus-thorn-%.git-tag: $(TARBALL_DIR)/cactus-thorn-source-%.files $(GIT-INIT-REPO) { \ echo "Formaline: Adding thorn $* to git repository..." && \ cd $(GIT-ROOT) && \ export GIT_DIR=$(GIT-REPO)/.git && \ { $(GIT) rm --cached -r arrangements/*/$* > /dev/null 2>&1 || true; } &&\ xargs ls < $(TARBALL_DIR)/cactus-thorn-source-$*.files \ > $(TARBALL_DIR)/cactus-thorn-source-$*.files2 2> /dev/null; \ xargs $(GIT) add < $(TARBALL_DIR)/cactus-thorn-source-$*.files2 && \ rm $(TARBALL_DIR)/cactus-thorn-source-$*.files2 && \ : > $@; \ } || echo "WARNING: Error while handling git repository" endif # NOTE: # Define environment variable CACTUS_CENTRAL_GIT_REPO where the source trees # are automatically pushed # git-archive --prefix=Cactus/ wavetoy | gzip > wavetoy.tar.gz # git-archive --prefix=Cactus/ wavetoy | { cd /somewhere && tar xf -; } # git init # git pull # git clone # git checkout # TODO: # DONE: # 1. Remember git-archive to get a tarball # 3. Push the commits automatically to a central (write-only?) repository # 4. What if the Cactus directory is alread the root of a git repository? # 5. Place the .git repository into the config subdirectory # 6. Push it automatically into a subdirectory of the main Cactus directory # 7. Figure out how to handle conflicting branch names # WONT: # 2. Don't create a version history; instead, leave all commits independent