I have a makefile, a part of which which looks like this:
.PHONY: all
all: master dispatcher
.PHONY: master
master: BUILDTARGET=master
master: buildbin ## Builds master
.PHONY: dispatcher
dispatcher: BUILDTARGET=dispatcher
dispatcher: buildbin ## Builds dispatcher
.PHONY: buildbin
buildbin:
#cd ${BUILD_FOLDER}/${BUILDTARGET} && ${MAKE} build GOBIN=${GOBIN}
LDFLAGS="${LDFLAGS}" CMD_FOLDER=${CMD_FOLDER}
#cd ${PROJECT_ROOT}
Please assume BUILD_FOLDER, GOBIN, LDFLAGS, CMD_FOLDER, PROJECT_ROOT to be set.
The trouble is running make always builds 'master' only and exits.
Changing the order of 'all', I found it was building the 1st one only.
What is wrong with the above Makefile.
You can't use dependencies like this, buildbin is just another target and will be remade at most once per invocation. You can fix this as follows:
.PHONY: all master dispatcher
all: master dispatcher
master: BUILDTARGET=master
dispatcher: BUILDTARGET=dispatcher
master dispatcher:
#cd ${BUILD_FOLDER}/${BUILDTARGET} && ${MAKE} build GOBIN=${GOBIN} LDFLAGS="${LDFLAGS}" CMD_FOLDER=${CMD_FOLDER}
#cd ${PROJECT_ROOT}
Or more simply
.PHONY: all master dispatcher
all: master dispatcher
master dispatcher:
#cd ${BUILD_FOLDER}/$# && ${MAKE} build GOBIN=${GOBIN} LDFLAGS="${LDFLAGS}" CMD_FOLDER=${CMD_FOLDER}
#cd ${PROJECT_ROOT}
Related
I have a makefile with the following lines:
debug: CFLAGS += $(DEBUGFLAGS)
debug: clean all
What I want to do is run 'clean' and 'all' with the Target Specific Variable values. This works fine and as expected.
But if I ran this with parallel execution 'clean' might destroy the files being create by 'all'.
So if I do something like the following:
debug: CFLAGS += $(DEBUGFLAGS)
debug:
$(MAKE) clean
$(MAKE) all
This will ensure that the order of the rules is respected. But the Target Specific Variables will not be taken into the new invocations of make.
So I was wondering how I can use both Target Specific Variables and parallel execution.
Why not just pass through the values as well?
debug: CFLAGS += $(DEBUGFLAGS)
debug:
$(MAKE) clean CFLAGS='$(CFLAGS)'
$(MAKE) all CFLAGS='$(CFLAGS)'
Not sure which version of make introduced it (3.8? 4.0?), but if you add 'clean' to the pseudo-target .NOTPARALLEL, then clean is not run in parallel, and other targets are. I use make -j clean all and this seems to work as expected.
e.g.
...<variables defined here>...
all: $(TARGETS)
clean:; rm -rf $(TARGETS) ...
...<rules defined here>...
.PHONY: all clean
.NOTPARALLEL: clean
Most makefiles have a structure such as this:
.PHONY: prebuild
all: $(TARGET)
prebuild: Makefile
$(shell DEPDIR=$(DEPDIR) mkdir -p $(DEPDIR)/../common >/dev/null)
# do other work related to preparing for the object files to be built such as run a script to modify a header file included by $(TARGET).c
$(TARGET): $(TARGET).c prebuild
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c
The implicit rules know how to build $(TARGET).o from $(TARGET).c, and doesn't do any work if $(TARGET).o is already newer than $(TARGET).c. This happens when make is run multiple times without changing the source file.
However, building the all target above will seemingly always rerun the $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c link to link the application and create the application binary. This happens even if that binary already exists and doesn't need to be recreated. In some larger projects, this process can take a long time (tens of seconds), which is sometimes not desirable.
Edit #1: The issue has to do something with an extra phony target that I do want to run ONCE before the object files are built. In my case, I'm running a script which takes Makefile variables and possibly updates a header file that is included in the C file. But, if the Makefile doesn't change, the prebuild target isn't run. However, the $(TARGET) target is still run even if prebuild doesn't do anything (for instance, because Makefile wasn't changed). FYI: because of the structure of my build system, I have prebuild run always because my build system is used for a variety of applications that can dynamically redefine prebuild.
How can this Makefile be restructured to not do the linking again when not necessary?
Edit #2:
Here's a simplified example that seems to illustrate my issue:
Before running, create a new directory and touch a b
.PHONY: prebuild main all
all: main
prebuild: a Makefile
#echo prebuild ran
main: prebuild
#echo main ran
When I run, I get this output:
prebuild ran
main ran
This is what happens no matter how many times I run make, even though the prerequisite a nor Makefile doesn't change. What I expect to happen is prebuild doesn't run (because a and Makefile don't change) and main also doesn't run because prebuild doesn't run. Clearly, I'm misunderstanding something.
The problem is that extra dependency triggering your rebuild.
Try this:
.PHONY: all
OUTPUTDIR=common/
TARGET=finalexe
all: $(OUTPUTDIR)/$(TARGET)
$(OUTPUTDIR)/$(TARGET): $(TARGET).c | $(OUTPUTDIR)
$(CC) $(CFLAGS) -o $# $(TARGET).c
$(OUTPUTDIR):
mkdir -p $#
In this above example, 'finalexe' will be created if A. it doesn't yet exist or B. if finalexe.c was modified. The timestamp on the OUTPUTDIR is not checked.
I am looking at a pre-existing, working, complex makefile for a project which will both build and deploy the code on multiple OS's.
I'm looking at some separate IDE support (Visual Studio) for the build process (i.e. half the make will already be done), so need to insert a phony target for the deploy action such that the old flow (make all) still works, including the deloy step, but that make deploy will just do the final deployment step for those using the IDE.
Not being familiar with make, I'm having difficulty seeing how/if make allows such an entry point and if so how to implement it.
The current code has:
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $# && \
ln $< $# 2>/dev/null || \
ln -s $< $# 2>/dev/null || \
cp $< $#
whose actions are the deployment step.
So conceptually I think I need
.PHONY: deploy
$(BUILT_INS): git$X
deploy
deploy:
$(QUIET_BUILT_IN)$(RM) $# && \
ln $< $# 2>/dev/null || \
ln -s $< $# 2>/dev/null || \
cp $< $#
which is clearly not right, because the phony target can't be an action.
In summary; How to create an entry point into a makefile to do the rule's actions? (a critical desire is to avoid duplicating the action code)
Your "conceptually" solution has many more problems than using a target as a recipe (which you're right, won't work, but you could fix by using $(MAKE) deploy as the recipe to invoke a recursive make); the other thing is that this:
$(BUILT_INS):
... using $# ...
means run that recipe one time for each word in the BUILT_INS variable, and each time the automatic variable $# will be assigned to that word (the target).
Your replacement:
deploy:
... using $# ...
does an entirely different thing: it runs the recipe one time, with the value of $# set to deploy. Not going to work.
The simple answer to your question is that you just declare a new target deploy that lists the targets you want to run as prerequisites:
.PHONY: deploy
deploy: $(BUILT_INS)
Now when you run make deploy it will try to build the BUILT_INS targets, and run the install rule for each one.
However, my suspicion is that this will be a problem for you, depending on what the git$X prerequisite is... it might cause a big part of the rest of your makefile to run as well. But, you don't give any information about that so I can't say.
ETA Sure enough, git$X is a problem. So, it appears you want VS to generate your git$X file (which will be git.exe presumably). Then you want to run make deploy to copy it. The trick here is to keep make from rebuilding git$X when you use the deploy target. You can do something like this; replace the rule that builds git$X with:
.PHONY: deploy
deploy: $(BUILT_INS)
ifeq (,$(filter deploy,$(MAKECMDGOALS)))
git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $# $(ALL_LDFLAGS) git.o \
$(BUILTIN_OBJS) $(LIBS)
endif
This creates a new target deploy which depends on the BUILT_INS targets, as I show above. Then, I enclose the rule to create git$X inside a test so that if you run make deploy that rule is not defined. Now make doesn't know how to build git$X at all, so if it doesn't exist then make deploy will fail, but if it does exist then make will copy it, without trying to rebuild it.
In the current system, there was a ghetto hack to initiate a parallel build for the system. For instance, to call a parallel make required make JOBS=8 instead of make -j8. I have since fixed the makefile, however there are a lot of previous dependencies on the JOBS flags within scripts that call make. I was hoping to recursively call make as a workaround as such:
ifdef JOBS
%:
$(MAKE) $(MAKECMDGOALS) JOBS= -j$(JOBS)
endif
This has some odd behavior though. It will first call make JOBS= -j8 as it should, but after this rule is completed it seems to go on and rebuild everything again that is in $(MAKECMDGOALS).
#Example
TARGETS = lib0 lib1 lib2
ifdef JOBS
%:
$(MAKE) $(MAKECMDGOALS) -j$(JOBS) JOBS=
endif
all: $(TARGETS)
lib%:
#echo g++ $#
Cmd: make JOBS=8.
This is fine for most rules, however it keeps wasting time rebuilding PHONY rules, so this should be fixed. Is there a way to completely reroute a make JOBS=N command to make -j$(JOBS) without executing any other rules redundantly in either scope? (meaning nothing executes except a submake in make JOBS=N, and the submake is only called once with all $(MAKECMDGOALS) at once.)
EDIT: I would also like to avoid large ifdef; else; endif statements, at the very most putting a self contained one at the top of the file. I'm starting to think the solution may require something like that though:
TARGETS = lib0 lib1 lib2
ifdef JOBS
%: unique_make
#echo $# built > /dev/null
.PHONY: unique_make
unique_make:
$(MAKE) $(MAKECMDGOALS) -j$(JOBS) JOBS=
else
all: $(TARGETS)
lib%:
#echo g++ $#
endif
In GNU make, you can modify the make flags within a Makefile. Why not try something like this:
ifdef JOBS
MAKEFLAGS+=-j$(JOBS)
endif
The question is about parallel making w/ GNU makefile.
Given a folder structure as below, the goal is to deliver a makefile that it supports make release/debug/clean in parallel.
project folder structure:
foo
+-foo1
+-foo2
+-foo3
The makefile may be sth like:
SUBDIR = foo1 foo2 foo3
.PHONY $(SUBDIR) release debug clean
release: $(SUBDIR)
$(SUBDIR):
$(MAKE) -C $# release
debug: $(SUBDIR)
#below is incorrect. $(SUBDIR) is overriden.
$(SUBDIR):
$(MAKE) -C $# debug
..
Sub directory list are set as phony targets for parallel making. but it lost the information of original target (release, debug, clean etc).
One method is to suffix the names for the directories and recover it in commands, but it is weird. another method might be to use variables, but not sure how to work it out.
The questions is:
How to write the rules for directories, that supports parallel making w/ different targets (release/debug/clean)?
Any hints are greatly appreciated.
Setting variables on the command line certainly works. You can also use MAKECMDGOALS (see the GNU make manual):
$(SUBDIR):
$(MAKE) -C $# $(MAKECMDGOALS)