Makefile compile a library in another directory when it doesn't exist or the directory has been modify - makefile

Hi i have a makefile that compiles my library and then compiles the program. What i want to do is that the makefile recompile alway i modify my library's files for that i thought in this
ifneq ("$(wildcard $(PATH_LIB.A)","")
FILE_EXIST = 1
else
FILE_EXIST = 0
endif
$(MAIN_PROCESS): $(PATH_LIB.A) check_lib
...thing to do...
$(PATH_LIB.a):
FILE_EXIST = 0
check_lib:
ifeq("$(FILE_EXIST)","0")
$(MAKE) -C $(PATH_MAKEFILE_LIB.A)
endif
My problem es that when i compile it relinks all time "...thins to do..." because is checking all time check_lib as updateable what do you suggest for do what i want to do?

Make is not a scripting language like bash or python. What it needs is a description of inter-dependencies between targets and prerequisites, plus recipes to build them. In your case (but I am not sure I understood all details) you could try:
$(MAIN_PROCESS): $(PATH_LIB.A)
...thing to do...
$(PATH_LIB.A):
$(MAKE) -C $(PATH_MAKEFILE_LIB.A)
And that's all (but continue reading, there is more to understand). This tells make that:
$(MAIN_PROCESS) depends on $(PATH_LIB.A), plus the things to do to build $(MAIN_PROCESS) if it does not exist or if it is older than $(PATH_LIB.A).
$(PATH_LIB.A) depends on nothing, plus what to do if it does not exist.
It almost works. Almost only because if $(PATH_LIB.A) already exists but is out of date (with respect to its own source files) it will not be rebuilt. A solution is to declare it as phony:
.PHONY: $(PATH_LIB.A)
$(MAIN_PROCESS): $(PATH_LIB.A)
...thing to do...
$(PATH_LIB.A):
$(MAKE) -C $(PATH_MAKEFILE_LIB.A)
This way make will always try to rebuild it, even if it already exists. The sub-make will do it if needed, else it will just tell you that it was up to date. But it is not the whole story: as make always tries to rebuild $(PATH_LIB.A), it will consider that $(MAIN_PROCESS) must also be rebuilt, even if the sub-make didn't do anything because $(PATH_LIB.A) was up-to-date.
If this is a problem, more tricky solutions can be used, like using one more sub-make. The idea is the following:
Use make conditionals to create two different contexts of invocation with two different rules for your $(MAIN_PROCESS) target.
On the first invocation of make, the first context is used where $(MAIN_PROCESS) depends on the phony $(PATH_LIB.A) but its recipe, instead of ...thing to do... is a second invocation of make, in the other context.
For this second invocation $(MAIN_PROCESS) depends on the non-phony $(PATH_LIB.A) and will have its normal recipe.
The two contexts are distinguished thanks to a dedicated make variable (SECONDPASS in the code below).
Example:
host> cat lib/Makefile
foo.a: foo.c
touch $#
host> cat Makefile
ifeq ($(SECONDPASS),)
$(MAIN_PROCESS): $(PATH_LIB.A)
$(MAKE) SECONDPASS=1
.PHONY: $(PATH_LIB.A)
$(PATH_LIB.A):
$(MAKE) -C $(dir $#)
else
$(MAIN_PROCESS): $(PATH_LIB.A)
touch $#
endif
host> make --no-print-directory
make -C lib/
touch foo.a
make SECONDPASS=1
touch bar
host> make --no-print-directory
make[1]: 'foo.a' is up to date.
make SECONDPASS=1
make[1]: 'bar' is up to date.
host> touch lib/foo.c
host> make --no-print-directory
make -C lib/
touch foo.a
make SECONDPASS=1
touch bar
host> touch lib/foo.a
host> make --no-print-directory
make -C lib/
make[1]: 'foo.a' is up to date.
make SECONDPASS=1
touch bar

Related

How to determine if Make target is a PHONY?

I have a make target that depends on a variable, which contains both PHONY and real targets.
This target needs to depend only on the real targets in the variable.
How can I test a variable to determine if it is a PHONY or not, so I can filter them out?
(I can test for a file's existence inside the recipe, but I don't want my target to be triggered by execution of any of the PHONY targets.)
Thanks!
There is a way to do it, but I would strongly recommend against it. First of, phony targets can be also file targets. And there is no way to tell a phony file target from a non-phony file target.
It looks like the question implies that the phony targets the author wants to ignore are all non-file targets. In this case see the example below.
.PHONY: phony_target .FORCE
.FORCE:
ALL_TARGETS = phony_target file_target undetermined_target
-include detect_phony.inc
all: final_target
# All done
final_target: $(REAL_TARGETS)
# create $# triggered by $?
#touch $#
ifeq (,$(MAKE_RESTARTS))
# Generate the list of real file targets in make include file
detect_phony.inc: .FORCE
#echo 'REAL_TARGETS = ' `ls $(ALL_TARGETS) 2>/dev/null` > $# |:
endif
file_target:
touch $#
undetermined_target phony_target:
# process $#
clean:
rm -f file_target final_target
Here are the test results:
$make clean
rm -f file_target final_target
$ make
# create final_target triggered by
# All done
$ touch file_target
$ make
# create final_target triggered by file_target
# All done
$ make
# All done
As you can see it only triggers the final target when the file target is updated.
Before you criticize - Here are the flaws of this implementation:
make is always called twice, updating the generated detect_phony.inc include file at every run
if detect_phony.inc gets corrupted somehow, make execution will be locked by syntax errors, until you manually delete it.
it can't handle phony file targets as I mentioned before
if another generated include is added in this makefile that requires another restart before detect_phony.inc this functionality will break.
So it this method is hacky and has several gotchas. I would not use it in production environment. I would insist on changing the top level Makefile first.

How to tell make to watch dependencies of a sub-make target?

I was investigating on the same question here, but I was not very clear of what I was asking, even for myself. Sorry for those who spent time answering my unclear question.
So let's try again with a more realistic example. We consider this structure:
.
├── Makefile
└── src/
├── bar
├── foo
└── Makefile
Where the main Makefile is:
all: src/foobar
src/foobar:
make -C $(dir $#)
And the sub-makefile is:
foobar: foo bar
join $^ > $#
If I run make for the first time (from ./) everything works as expected, foobar is produced.
$ make
make -C src/
make[1]: Entering directory '/project/src'
join foo bar > foobar
make[1]: Leaving directory '/project/src'
$ make
make: Nothing to be done for 'all'.
However if I touch any of the foobar dependencies. The parent Makefile will not regenerate the target. Here, I perfectly understand the behavior of Make, but I want to tell it to be aware of foobar' dependencies.
$ touch src/foo
$ make
make: Nothing to be done for 'all'.
My current solution which is not very neat is to ask for the dependencies. So the src/Makefile become:
src=foo bar
foobar: $(src)
#echo "Joining"
join $^ > $#
files: $(src)
#echo $^
And the ./Makefile:
all: src/foobar
src=$(addprefix src/,$(shell make --no-print-directory -C src files | tr '\n' ' '))
src/foobar: $(src)
make -C $(dir $#)
I must also say that this particular example could be simplified using a single Makefile only. My real example is quite more complex. The src/Makefile generate an executable while the parent Makefile do lots of other things (packing in a specific format, generate the documentation, build other sub-makefiles and so on). Thus, I want to keep these tasks well separated and I need to different Makefiles.
In the main Makefile create a dependency for the child target or directory that is always in need of building, and let the child Make then do the real work.
There is a good example here: http://owen.sj.ca.us/~rk/howto/slides/make/slides/makerecurs.html.
To translate for your case, change your main Makefile to be:
all: src/foobar
src/foobar: force
$(MAKE) $(MFLAGS) -C src
force:
true
I also added $(MFLAGS) which will pass same flags from parent to child make.

Change make's working directory without long command line

I would like to change the working directory of a makefile.
(Extraneous info: I have a legacy makefile that I mostly want to reuse, though many targets and generated deps files make assume that the working directory will not be different. My idea is to create a makefile for my newer project, which is in a different directory, and include the old one, and set the working directory to the old directory.)
I easily can do this from the command line with
make -f /path/to/new/makefile -C /path/to/old/makefile
The users of this makefile would like not to type that out every time.
Attempt 1
Use MAKEFLAGS in the makefile itself. But neither of these seem to have any effect. (I understand why -f couldn't have an effect; I'm really wondering about -C.)
I've looked at http://www.gnu.org/software/make/manual/html_node/Options-Summary.html, but I can't find anything about what is allowed in MAKEFLAGS and what isn't.
Attempt 2
Create a makefile2 with the new targets
include path/to/old/makefile
foo: bar
and then makefile passes everything through
%:
$(MAKE) -f $(abspath makefile2) -C path/to/old/makfele /$*
I don't get nice autocompletion, parallel jobs don't work, and debug options (dry run) doesn't work.
So
(1) Why doesn't -C work MAKEFLAGS (it does work, but I made a mistake; it doesn't work, and it is documented; it doesn't work, and it is not documented but it is intentional; it doesn't work, and it is a bug)?
(2) Is there a better way of change a makefile's working directory?
Some things are wrong here :
make -f /path/to/new/makefile -C /path/to/old/makefile
The -f options specifies the name of the Makefile to be found when searched in the directory specified with -C (or the current directory if not provided). So it is more :
make -C /path/to/old/Makefile -f name_of_old_makefile
If the name is simply Makefile or makefile, there is no need to provide the -foption.
The MAKEFLAGS variable does not contains -f or -C in the called sub-Makefile.
To be able to pass multiple targets to another makefile, you need the MAKECMDGOALS variable.
Ultimately, all you have to do in your new Makefile is to have someting like this :
all:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $#
%:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $(MAKECMDGOALS)

Run make in each subdirectory

I have a directory (root_dir), that contains a number of sub-directories (subdir1, subdir2, ...).
I want to run the make in each directory in root_dir, using a Makefile placed in it.
(Obviously supposed that each of subdir... has inside its own Makefile).
So there are essentially two questions:
How to get a list of directories in Makefile (automatically)?
How to run make for each of the directories inside a make file?
As I know in order to run make in a specific directory I need to do the following:
$(MAKE) -C subdir
There are various problems with doing the sub-make inside a for loop in a single recipe. The best way to do multiple subdirectories is like this:
SUBDIRS := $(wildcard */.)
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
.PHONY: all $(SUBDIRS)
(Just to point out this is GNU make specific; you didn't mention any restrictions on the version of make you're using).
ETA Here's a version which supports multiple top-level targets.
TOPTARGETS := all clean
SUBDIRS := $(wildcard */.)
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# $(MAKECMDGOALS)
.PHONY: $(TOPTARGETS) $(SUBDIRS)
Try this :
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
This may help you link
Edit : you can also do :
The simplest way is to do:
CODE_DIR = code
.PHONY: project_code
project_code:
$(MAKE) -C $(CODE_DIR)
The .PHONY rule means that project_code is not a file that needs to be
built, and the -C flag indicates a change in directory (equivalent to
running cd code before calling make). You can use the same approach
for calling other targets in the code Makefile.
For example:
clean:
$(MAKE) -C $(CODE_DIR) clean
Source
This is another approach to MadScientist's answer. .PHONY is a GNU-specific feature that can be used to force make into recursing into each subdirectory. However, some non-GNU versions of make do not support .PHONY, so an alternative is a force target.
4.7 Rules without Recipes or Prerequisites
If a rule has no prerequisites or recipe, and the target of the rule
is a nonexistent file, then make imagines this target to have been
updated whenever its rule is run. This implies that all targets
depending on this one will always have their recipe run.
An example will illustrate this:
clean: FORCE
rm $(objects)
FORCE:
Here the target ‘FORCE’ satisfies the special conditions, so the
target clean that depends on it is forced to run its recipe. There is
nothing special about the name ‘FORCE’, but that is one name commonly
used this way.
As you can see, using ‘FORCE’ this way has the same results as using
‘.PHONY: clean’.
Using ‘.PHONY’ is more explicit and more efficient. However, other
versions of make do not support ‘.PHONY’; thus ‘FORCE’ appears in many
makefiles. See Phony Targets.
The following is a minimal example that recurses make into each subdirectory, each of which presumably contains a Makefile. If you simply run make, only the first subdirectory, which is non-deterministic, is processed. You may also run make subdir1 subdir2 ....
# Register all subdirectories in the project's root directory.
SUBDIRS := $(wildcard */.)
# Recurse `make` into each subdirectory.
$(SUBDIRS): FORCE
$(MAKE) -C $#
# A target without prerequisites and a recipe, and there is no file named `FORCE`.
# `make` will always run this and any other target that depends on it.
FORCE:
Here is another example with top-level phony targets: all and clean. Note that the all and clean targets, passed from command-line via $(MAKECMDGOALS), are handled by each subdirectory's all and clean targets respectively.
# Register all subdirectories in the project's root directory.
SUBDIRS := $(wildcard */.)
# Top-level phony targets.
all clean: $(SUBDIRS) FORCE
# Similar to:
# .PHONY: all clean
# all clean: $(SUBDIRS)
# GNU's .PHONY target is more efficient in that it explicitly declares non-files.
# Recurse `make` into each subdirectory
# Pass along targets specified at command-line (if any).
$(SUBDIRS): FORCE
$(MAKE) -C $# $(MAKECMDGOALS)
# Force targets.
FORCE:
You can also define a function in the Makefile (also you of course need an additional makefile in each subdirectory). This is shell-dependent, but can be useful:
define FOREACH
for DIR in packages/*; do \
$(MAKE) -C $$DIR $(1); \
done
endef
.PHONY: build
build:
$(call FOREACH,build)
.PHONY: clean
clean:
$(call FOREACH,clean)
.PHONY: test
test:
$(call FOREACH,test)
Only a small icing on the cake after MadScientist's answer in order to make all the individual targets in the sub-directories available from the top level (you will need to have the SUBDIRS variable defined in order to use the following snippet – you can use MadScientist's answer for that):
# Make all the individual targets in the sub-directories available from the top
# level; as in, for instance, `make foo/my_program` or `make bar/clean`
$(foreach __dir__,$(SUBDIRS),$(__dir__)/%):
#$(MAKE) -C '$(#D)' '$(#F)'
With the code above you can run, for instance,
make foo/my_program
or
make bar/clean
Furthermore, by pasting the code above you can even use an individual target from a sub-directory as a prerequisite for a target in the top level. For example:
my_target: my_subdirectory/my_prerequisite
'my_subdirectory/my_prerequisite' > 'my_target'
…With the example above, launching make my_target from the top level will first build the my_subdirectory/my_prerequisite program, then the latter will be run for building the my_target file.
Since I was not aware of the MAKECMDGOALS variable and overlooked that MadScientist has its own implementation of multiple top-level targets, I wrote an alternative implementation. Maybe someone find it useful.
SUBDIRS := $(wildcard */.)
define submake
for d in $(SUBDIRS); \
do \
$(MAKE) $(1) --directory=$$d; \
done
endef
all:
$(call submake,$#)
install:
$(call submake,$#)
.PHONY: all install $(SUBDIRS)
There is a library called prorab for GNU make which supports inclusion of standalone makefiles in subdirectories.
Some info on github: https://github.com/cppfw/prorab/blob/master/wiki/HomePage.adoc
Basically, with prorab invoking all makefiles in subdirectories looks like this:
include prorab.mk
$(eval $(prorab-build-subdirs))
In reference to https://stackoverflow.com/posts/17845120/revisions
This is what I learned from that post.
Top Level Makefile
# set the default goal.
# I want the default to really just dump contents of dirs
# as a stub. For instance, I don't want it to
# push code or
.DEFAULT_GOAL := deploy
TOPTARGETS := all clean
SUBDIRS := docs src
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
echo "make arg is" $(MAKECMDGOALS)
$(MAKE) -C $# $(MAKECMDGOALS)
SUBCLEAN = $(addsuffix .clean,$(SUBDIRS))
clean: $(SUBCLEAN)
$(SUBCLEAN): %.clean:
$(MAKE) -C $* clean
deploy:
echo do deploy stub
The src/ and docs/ common to this Makefile directory, all have a corresponding Makefile.
Here is an example of the docs setup:
# set the default goal.
.DEFAULT_GOAL := list_docs
list_docs:
ls -l
clean:
echo "docs: make clean"
-rm "*.backup"
I did this a little different than any of the answers because I didn't want to have to define each possible make target
SUBDIRS := $(patsubst %/,%,$(wildcard */))
.PHONY: all $(MAKECMDGOALS) $(SUBDIRS)
$(MAKECMDGOALS) all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $# $(MAKECMDGOALS)

How to force make to always rebuild a file

I have a version.c file in my project that contains current revision of the project and some other stuff that is passed as a definition (-D compiler option) from makefile.
I know that to force make to compile version.c always regardless of modification date I can touch version.c.
Is there a makefile only way to achieve this? If I write .PHONY : version.o the object file doesn't get build at all.
EDIT:
Here is my makefile:
export CC = gcc
export MODULES = $(sort \
sys \
cim \
version \
)
export FILES = $(sort \
main.c \
cim.c \
version.c \
)
VPATH = $(MODULES)
OBJS = $(FILES:.c=.o)
INCLUDES = $(addprefix -I,$(MODULES))
all:$(OBJS)
$(CC) $(INCLUDES) $(OBJS) -o main.exe
clean:
rm -rf *.o *.exe
cim.o: cim.c
main.o: main.c cim.o
version.o: version.c
.PHONY: version.o
.c.o :
$(CC) $(CFLAGS) $(INCLUDES) -c $<
The classic way to do it is:
version.o: .FORCE
.FORCE:
(and you might add .PHONY: .FORCE). The file '.FORCE' is presumed not to exist, so it is always 'created', so version.o is always out of date w.r.t it, so version.o is always compiled.
I'm not sure that making version.o into a phony file is correct; it is actually a real file, not a phony one.
Not a makefile way, but easier than touch:
make -B
‘-B’ ‘--always-make’
Consider all targets out-of-date. GNU make proceeds to consider targets and their prerequisites using the normal algorithms; however,
all targets so considered are always remade regardless of the status
of their prerequisites. To avoid infinite recursion, if MAKE_RESTARTS
(see Other Special Variables) is set to a number greater than 0 this
option is disabled when considering whether to remake makefiles (see
How Makefiles Are Remade).
If you want to do this using the FORCE mechanism the correct solution looks like this:
version.o: FORCE
.PHONY: FORCE
FORCE:
By explicitly declaring FORCE to be phony we make sure things will work right even if .SECONDARY: is used (.SECONDARY: will cause FORCE to be considered an intermediate file, and make doesn't rebuilt intermediate files unless they have prerequisites newer than the ultimate target, and FORCE doesn't have any prerequisites, so .PHONY: FORCE is needed).
The other solution (using $(shell touch version.c)) also has a problem: it may cause your editor to think version.c has been updated, and prompt for a reload of the file, which might end up being destructive if you've been editing the file's buffer but haven't yet saved it. If you don't mind this, it can be made even simpler by observing that the touch command is silent, so the assignment to the hack dummy variable isn't needed:
$(shell touch version.c) # This is enough, but will likely confuse your editor
The .PHONY "trick" referred to in the comments on the question generally DOES NOT work. It may look like it does because it will force a relink iff version.o already exists, but the actual object file won't get rebuilt if the .o file rule is an implicit rule (which it usually is). The problem is that make doesn't do the implicit rule search for explicitly phony targets. This make file shows the failure:
fooprog: test.o
cp $< $#
%.o: %.c
cp $< $#
.PHONY: test.o # WRONG
clean:
rm test.o fooprog
If a static pattern rule is used instead of an implicit rule the .PHONY: version.o trick will work. In general using static pattern rules instead of implicit rules cuts out most of the more confusing Make behaviors. But most make files use implicit rules.
The quick hack version when you just need it to work and you don't want to play Make games:
# Hack to get main.c rebuilt
hack := $(shell touch main.c)
Basically just make Make run touch for you.

Resources