What's the difference between:
ar -x liba.a
ar -x libb.a
ar rcs libab.a *.o
and
ar rcs libab.a liba.a libb.a
Are they really doing the same task?
Unless you're using a version of ar that I don't know about, the effects of the two sequences of commands are quite different — though both end up creating a file libab.a.
The first sequence extracts all the (object) files from liba.a into the current directory, then all the files from libb.a (any name collisions mean the file from libb.a will survive), and then all the object files that are now in the directory (possibly including ones that were in neither liba.a nor libb.a) are archived in libab.a.
The second sequence creates an archive that itself contains two files: liba.a and libb.a. This is legal and feasible, but the resulting file isn't useful in linking programs. The linker doesn't look at nested archives; it will simply find no object files that supply any symbols (since neither liba.a nor libb.a is an object file), so the library will effectively be unused — though you'll not get an error from attempting to use it.
It is more likely that the first sequence of commands is useful than the second.
Related
Referring to https://www.gnu.org/software/make/manual/make.html#Automatic-Variables
$?
The names of all the prerequisites that are newer than the target, with spaces between them. If the target does not exist, all prerequisites will be included. For prerequisites which are archive members, only the named member is used (see Archives).
$^
The names of all the prerequisites, with spaces between them. For prerequisites which are archive members, only the named member is used (see Archives). A target has only one prerequisite on each other file it depends on, no matter how many times each file is listed as a prerequisite. So if you list a prerequisite more than once for a target, the value of $^ contains just one copy of the name. This list does not contain any of the order-only prerequisites; for those see the ‘$|’ variable, below.
The 2 operators look very similar and so I am wondering when they will be different.
In our code base we have a code generator which takes foo.xyz and produces two source files foo-in.c and foo-out.c.
In an application's Makefile I would like to list the sources as:
SOURCES=main.c gadget.c foo.xyz
Then the corresponding OBJECTS variable should expand to:
OBJECTS=main.o gadget.o foo-in.o foo-out.o
but I'm unable to find whether it is possible to do this expansion generically using GNU Make. The common $(SOURCES:.c=.o) replacement pattern replaces a single source file with a single object file.
How can I write a substitution pattern which will produce multiple output files per input file?
Well, while writing the question I found a usable solution.
SOURCES=main.c gadget.c foo.xyz
OBJECTS=$(patsubst %.c,%.o,$(filter %.c,$(SOURCES))) \
$(patsubst %.xyz,%-in.o,$(filter %.xyz,$(SOURCES))) \
$(patsubst %.xyz,%-out.o,$(filter %.xyz,$(SOURCES)))
app: $(OBJECTS)
$(LD) -o $# $(LDFLAGS) $(OBJECTS)
%-in.c %-out.c: %.xyz
# Very special codegen rule
touch $(patsubst %.xyz,%-in.c,$<)
touch $(patsubst %.xyz,%-out.c,$<)
When converting from $(SOURCES) to $(OBJECTS) use two separate patsubst calls to the filteres out .xyz files. This way, both the %-in.o and %-out.o files ends up in the object list.
Another solution could be to create an intermediate sources list using the same trick but substituting xyz with the corresponding -in.c and -out.c patterns. Then the objects list could be created in the traditional way. An added benefit of this method would be that creating a rule which generates all source code files is trivial.
I am thinking I may need to use the file function in GNU make, and just can not follow the example they give. I have looked online, but don't see any post with more explanation. Here is the example they give:
program: $(OBJECTS)
$(file >$#.in,$^)
$(CMD) $(CMDFLAGS) #$#.in
#rm $#.in
I think I know what it is doing at a high level as it is explained in the manual.
$#.in
is a list of all the target files
$^
is a list of the source files
I am not sure how #$#.in is used on the third line or what there is an # sign at the beginning. What does that mean please? What does it supposed to do?
The key to the operation of that recipe is given in the prose immediately preceding it in the manual:
Many commands use the convention that an argument prefixed with an # specifies a file containing more arguments. Then you might write your recipe in this way:
program: $(OBJECTS)
$(file >$#.in,$^)
$(CMD) $(CMDFLAGS) #$#.in
#rm $#.in
$# is the target file (there is only one of those in any given recipe)
$#.in is the target file with .in added to the end of the name.
$^ is the "list" of the all the prerequisites of the target.
#$#.in is the name of the target with .in at the end and # at the start.
So the $(file ...) call in that recipe writes the list of prerequisites of the target into a file called program.in in "overwrite" mode and then passes that file name to the $(CMD) command using the #filename convention that was mentioned.
I would like to have a makefile like this:
cudaLib :
# Create shared library with nvcc
ocelotLib :
# Create shared library for gpuocelot
build-cuda : cudaLib
make build
build-ocelot : ocelotLib
make build
build :
# build and link with the shared library
I.e. the *Lib tasks create a library that runs cuda directly on the device, or on gpuocelot respectively.
For both build tasks I need to run the same build steps, only creating the library differs.
Is there an alternative to running make directly?
make build
Kind of a post-requisite?
Note: This answer focuses on the aspect of a robust recursive invocation of a different target in a given makefile.
To complement Jack Kelly's helpful answer, here's a GNU makefile snippet that demonstrates the use of $(MAKE) to robustly invoke a different target in the same makefile (ensuring that the same make binary is called, and that the same makefile is targeted):
# Determine this makefile's path.
# Be sure to place this BEFORE `include` directives, if any.
THIS_FILE := $(lastword $(MAKEFILE_LIST))
target:
#echo $# # print target name
#$(MAKE) -f $(THIS_FILE) other-target # invoke other target
other-target:
#echo $# # print target name
Output:
$ make target
target
other-target
Using $(lastword $(MAKEFILE_LIST)) and -f ... ensures that the $(MAKE) command uses the same makefile, even if that makefile was passed with an explicit path (-f ...) when make was originally invoked.
Note: While GNU make does have features for recursive invocations - for instance, variable $(MAKE) specifically exists to enable them - their focus is on invoking subordinate makefiles, not on calling a different target in the same makefile.
That said, even though the workaround above is somewhat cumbersome and obscure, it does use regular features and should be robust.
Here is the link to the manual section covering recursive invocations ("sub-makes"):
Recursive Use of make
Most versions of make set a variable $(MAKE) that you can use for recursive invocations.
As you have written it, the build target will need to do something different depending on whether you have just done an ocelot or cuda build. That's another way of saying you have to parameterise build in some way. I suggest separate build targets (much like you already have), with associated variables. Something like:
build-cuda: cudaLib
build-ocelot: ocelotLib
build-cuda build-ocelot:
shell commands
which invoke ${opts-$#}
On the command-line you type make build-cuda (say). Make first builds cudaLib, then it carries out the recipe for build-cuda. It expands the macros before calling the shell. $# in this case is build-cuda, thus ${opts-$#} is first expanded to ${opts-build-cuda}. Make now goes on to expand ${opts-build-cuda}. You will have defined opts-build-cuda (and of course its sister opts-build-ocelot) elsewhere in the makefile.
P.S. Since build-cuda et. al. are not real files, you had better tell make this (.PHONY: build-cuda).
Essentially, what I want to do is this:
gcc foo.c -o foo.o
ar rcs foo.a foo.o
gcc bar.c -o boo.o
ar rcs bar.a bar.o foo.a
I want to archive both an object and a static library into another static library. Unfortunately, the last command doesn't end up containing foo.o (it contains bar.o and foo.a), so when I get to the linking stage, the linker can't find the symbols from foo.o.
Is there a way to do what I want here? I'm doing all of this out of make, so I'm looking for a solution that doesn't involve extracting & re-archiving the objects (which seems kinda painful). Is there a way to make this kind of "archive from another archive" setup work?
Actually, you do not want to archive one whole '.a' file inside another. You might want to archive the members of the one archive in the other - but that is a wholly different operation.
The 'ar' program is perfectly capable of storing source files, gzipped tar files, HTML files, XML files, and pretty much any other type of file in the '.a' (and the '.a' suffix is only conventional, not mandatory) -- try it some time. However, it treats object files (and only object files) specially, and makes them available for use by the linker ('ld'), but the linker only uses such files if the extension is '.a'.
So, you want to have two libraries:
foo.a containing just foo.o
bar.a containing bar.o and all the objects from foo.a
Short of doing as you suggest and extracting the objects from foo.a and building them into bar.a, the only alternative is to list the members of foo.a as members of bar.a too:
FOO_OBJS = foo.o
BAR_OBJS = bar.o $(FOO_OBJS)
foo.a: $(FOO_OBJS)
$(AR) $(ARFLAGS) $# $(FOO_OBJS)
bar.a: $(BAR_OBJS)
$(AR) $(ARFLAGS) $# $(BAR_OBJS)
I am assuming that your example is minimized. If it is not, then why bother with two libraries. Anything that uses just code from foo.o will only link foo.o even if given bar.a to link with. (It would be slightly different if these were shared objects, but it would probably still be better to use just one rather than two shared objects.)
ar rcs foo.a foo.o
cp foo.a foo2.a
gcc -c bar.c
ar rs foo2.a bar.o
And perhaps use foo.a instead of foo2.a if you don't need to keep it in its original form.