GNU make with VPATH: target which appears circular, but really shouldn't be - makefile

I have a rule in my Makefile which is intended to create a symlink to a file in a different directory:
VPATH = ../source
foo: foo
ln -s $< $#
Even though I intend for the target to resolve to ./foo and the dependency to resolve to ../source/foo, I understand why make sees it as circular. Is there a way to express this rule in a way that is not circular?

Note that the link does not depend on the changes of the link target; it only needs to exist. Therefore, there is no ordinary prerequisite needed at all, and the simplest fragment to do what you want would be
foo:
ln -sf ../source/$#
However, this won't work correctly if you still need your VPATH for other purposes. If that is so, then it seems to me the simplest way would be to ignore VPATH for this rule by using absolute path:
VPATH := ../source
$(CURDIR)/foo:
ln -sf ../source/$(#F)
Finally, if the file ../source/foo is also a target which is generated by Make, then maybe the best way would be:
VPATH := ../source
.SECONDEXPANSION:
$(CURDIR)/foo: | ../source/$$(#F)
ln -sf $|
Note that we are not depending on the changes of the prerequisite here, only on the existence of it.
By the way, the reason why I am using -f option is because, Make should support -B option. That option will not work unless you use -f here.

I think what you're trying here falls under the category of "VPATH abuse".
My experience is repeatedly pointing me toward the mantra "explicit is better than implicit" and this is one of the reasons why. Contrary to the assertions in the GNU make Manual, my experience has led me to believe that in larger, more complex projects, you need to be more explicity, not less, because the size makes it more difficult to locate files, unless their path is explicit.
I also believe that a lot of the need to use VPATH stems from the use of recursive make, where you're not building complete dependency trees; write your build system properly and you just don't need VPATH at all.
On a related subject, I'm a firm believer in only specifying one or two -I directories: your top-level src/ and include/ directories and make all inclussions relative to these paths. Again, on larger, more complex projects, seing #include "my/really/cool/thing.h" is soooo much informative than simply #include "thing.h".
That said, I am open to the idea of using VPATH for libraries, especially system libraries, because you can use the -lfoo syntax, but I wouldn't want to use it as a general rule, because it could threaten build reproducibility.

Related

Symbols ($(bindir), $(sysconfdir),...) unknown in (sub) Makefiles

I'm working with autotools for the first time, for a tool that's written in perl (SQLTeX), so only installation is required, no compilation.
The toplevel contains a simple Makefile.am:
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src man doc
EXTRA_DIST = README.md
.PHONY: all-am
all-am:
#echo "Done!"
If I create Makefile.am files in the sub-directories too, nothing seems to happen there so I just stick to Makefile. A snippet from src/Makefile (EDIT: this file is now renamed to Makefile.am):
SQLTeX: SQLTeX.pl
cat $^ | sed -e 's#{PERLDIR}#$(PL)#;s#{SYSCONFDIR}#$(sysconfdir)#' > $#
#chmod +x $#
The symbol PL is set as expect (defined in the same makefile), but sysconfdir is empty, although it is defined in the top-level Makefile generated by ./configure.
What am I doing wrong?
Thanks in advance!
What am I doing wrong?
Although the Autotools support, with some caveats, recursing into directories where you provide pre-built makefiles, you cannot expect those pre-built makefiles to be able to rely on autotools-provided variables such as the standard directory variables bindir and sysconfdir. Thus, although it is allowed to rely on hand-written makefiles in subdirectories, this is probably a false trail for you.
I recommend going back to this:
If I create Makefile.am files in the sub-directories too, nothing seems to happen there
and working out what's wrong. The Autotools definitely support generating recursive build systems, and one Makefile.am per directory is part of the usual approach to that. If it didn't work for you then my first guess would be that you forgot to list the extra makefiles in your AC_CONFIG_FILES list.
As an alternative, just because you have multiple directories does not mean that you need to use recursive make. It is quite possible to build such a project with the support of a single makefile, and the Autotools can help with such a makefile.

Make and VPATH. Why are my source files being placed where I don't want them?

I am trying to compile with make. I have source in two directories, src and altsrc. I want make to look in altsrc for source files first, and then in src. I want the objects to go into directory obs. The relevant parts of my Makefile looks like:
VPATH=altsrc:src:obj
$(A_OUT): $(OBS)
$(FORTRAN) -o $(A_OUT) $(OBS) $(LFLAGS)
obs/%.o: %.f
$(FORTRAN) $(FFLAGS) $< -o $#
This Makefile actually compiles the code OK, but it has one really obnoxious side effect: It finds each source file (and there are alot) and copies them out of altsrc or src into the directory where I am running make. This is really annoying and leads to a bunch of confusion later on. I haven't found any documentation anywhere that says this should be an effect of the VPATH macro. Can anyone tell me how to solve this? Thanks.
The trouble is that Make is RCS-savvy, and will check to see if a source file (e.g. td.f) can and should be updated from RCS. Yes, Make knows how to use co. If the source file isn't in such an archive (such as the source files in altsrc), then Make shrugs and gets on with the work.
The quickest, dirtiest solution is to use make -r. This will disable the built-in rules, which should solve the problem nicely... unless you rely on the built-in rules elsewhere.
If that won't do, you can override that particular rule with a do-nothing rule of your own, or with a rule that actually updates the sources in place, or you can touch the sources so that Make won't consider them out of date, or put the RCS files someplace where Make can't see them, or maybe two or three other options.

I Want my makefile to be more order independent!

This is related to my previous question: Why does .PHONY not work in this situation?.
I have a makefile system that I wrote to make it easy for developers who are not familiar with make, to do their tasks. In short, there is a generic portion which would be the same for all projects, and a set of makefiles that are specific for a given project. The project specific ones include the generic ones. It worked great on make 3.80 for some reason, but when I tried it out on make 3.81 I ran into a few problems. That forced me to make changes that are mentioned in the above post. Now I have some new problems, so I decided to make another post. Like in that post, I made a much smaller and simpler set of makefiles that show the problem. Unfortunatly, the "simple" case consists of 6 files. Sorry about that. First I'll start with the "project specific" ones (these are meant to be simple):
makefile:
TARGETS:=\
Lib1.mk \
Lib2.mk \
my_prog.mk \
include generic/top.mk
Lib1.mk:
BINARY:=Lib1
TYPE:=LIB
LOCATION:=a/location
include generic/rules.mk
Lib2.mk:
BINARY:=Lib2
TYPE:=LIB
LOCATION:=another/location
LIBS:=Lib1
include generic/rules.mk
my_prog.mk:
BINARY:=my_prog
TYPE:=EXE
LOCATION:=some/location
LIBS:=Lib1 Lib2
include generic/rules.mk
A quick description: Makefile simply lists the names of all the targets. A target is either a executable or a library. BINARY is the name of the library or executable (extensions are added by the generic part). TYPE is either EXE or LIB. LOCATION is where the binary should go. LIBS is whatever libraries this binary depends on. The real ones handles creating all the -L, rpath, etc. stuff for the user (as well as their equivalents for visual studio). Now for the generic ones (these do the REAL work):
generic/top.mk:
ALL_BINS:=
.PHONY: all
all:
include $(TARGETS)
all: $(ALL_BINS)
%.so %.exe:
mkdir -p $(dir $#)
touch $#
clean:
rm -rf out
and finally..
generic/rules.mk:
ifeq (EXE,$(TYPE))
$(BINARY).FULL_FILE_NAME:=out/$(LOCATION)/$(BINARY).exe
else
$(BINARY).FULL_FILE_NAME:=out/$(LOCATION)/lib$(BINARY).so
endif
$(BINARY).DEP_LIBS:=$(foreach a,$(LIBS),$($(a).FULL_FILE_NAME))
ALL_BINS+=$(BINARY)
$(BINARY): $($(BINARY).FULL_FILE_NAME)
$($(BINARY).FULL_FILE_NAME): $($(BINARY).DEP_LIBS)
BINARY:=
LOCATION:=
LIBS:=
Ok, in this state, things work fine. Make handles all the dependencies correctly, and if I touch any of the files, it will correctly "build" only the ones that it has to, and nothing more. The problem happens when you take the m_prog.mk line from makefile and move it to the top of the list, like so:
TARGETS:=\
my_prog.mk \
Lib1.mk \
Lib2.mk \
The problem seems to be that while its is going through rules.mk for my_prog.mk it does not yet know what the full library path for Lib1 and Lib2 (they are empty strings). So in the end, it considers my_prog to be dependent on nothing and it tries to build it out of order. In this example, you just see it "touch" my_prog first and then the other 2. Of course, when I have real compiler and linker commands in there, it throws an error.
Back when I simply had the .PHONY targets depend on each other (so my_prog depended on Lib1 and Lib2) life was easy and harmonious. Now that I can't do that, life became more difficult.
You may say, "heck just put it in the right order!". Well up to now, this has been handled automatically through make for the end users. In fact, most customers have been putting things in alphabetical order. They don't know or care what order they depend on each other. It would stink to have to tell them to re-order all of that now. Sorry for the length of this post. I'd appreciate any answers!
If you set variables using the := assignment operator, the assignment is evaluated immediately.
If you set variables using just = as the assignment operator, they're evaluated lazily, as late as possible (at the time of actual use).
See http://www.gnu.org/software/automake/manual/make/Flavors.html.
There are several ways to do what you want. The cleanest is probably by using vpath. Just modify rules.mk:
$(BINARY).DEP_LIBS:=$(foreach a,$(LIBS),$(a).so)
ALL_BINS+=$(BINARY)
vpath %.so out/$(LOCATION)

BSD Make and GNU Make compatible makefile

I have a BSDmakefile and GNUmakefile that are pretty much identical except for dependency management.
The GNUmakefile:
ifneq ($(MAKECMDGOALS), "clean")
-include $(dependencies)
endif
The BSDmakefile:
.for i in $(dependencies)
.sinclude "${i}"
.endfor
Is there a way to make it so that I can detect if I am running under gmake or bsdmake and then execute the appropriate include statements based off of that? I remember seeing someone take advantage of a quirk in both makefile processors so that they could achieve a similar effect.
Alternatively, if there is a better approach than this, I would like to know! (switching to SCons or CMake is not appropriate!)
Thanks!
You could put your GNU-specific stuff in GNUmakefile, your BSD-specific stuff in BSDmakefile, and your common stuff in a file named Makefile.common or similar. Then include Makefile.common at the very beginning of each of the other two. Downside is, now you have 3 makefiles instead of 2. Upside, you'll only be editing 1.

Separating objects and source with a makefile

I have been having troubles getting my makefiles to work the way I want. First off, I would like to say this is POSIX make, as in http://www.opengroup.org/onlinepubs/009695399/utilities/make.html I am needing my build system to work with both BSDs and GNUs(Linux).
What I am wanting is a zero maintenance makefile. I want it to just compile all .c and .asm files in src/ and place the object files in objs/ and then to link everything in objs/ to a binary file.
I can do a lot, but I can't get it to separate the source and obj files.
I am ok if this requires a little built-in shell scripting (using POSIX defined /bin/sh), but I can just not get the dependencies to work right. I want it to only build the object file if the source file is newer.
My closest is this:
${C_OBJS}: ${HDRS} ${*:objs/%=src/%}.c
${CC} ${CFLAGS} -c ${*:objs/%=src/%}.c -o $*.o
This has the problem that I must still specify C_OBJS=objs/foo.o and such and also it is just barely not POSIX and therefore, compiles with BSD make but not GNU make.
The POSIX version of make does not explicitly support file names with slashes in them, nor does it make provision for separating source files in a different directory from the object files. And, as noted by #caskey, it does not support any notation using '%' characters, though it notes that such rules exist and recommends that they be reserved for use as metacharacters.
Consequently, you probably cannot do what you want with standard POSIX make.
In practice, you can often do what you seek with specific implementations of make, but the resulting makefile has limited portability.
Consider using a makefile generation systems of some sort - cmake or the auto-tools (autoconf, libtool, automake, etc). Or one of the many reworkings of the basic concepts of make:
scons
ant
cake
cook
bras
...and a dozen I've forgotten or not heard of...
POSIX make doesn't support constructs like?
objs/%.o : src/%.c
${CC} ${CFLAGS} -c $< -o $#
Forgot the question mark at the end, hope that makes my comment more clear.

Resources