GNU make generate assembly first, them compile them to .o and link - gcc

SOURCE=a.c b.c c.c
ASM=$(patsubst %.c,%.s, $(SOURCE))
all:%.o
gcc -o test $^
$(ASM):%.c
gcc -S -o $# $<
%.o:%.s
gcc -c -o$# $<
I want to generate assembly code (.s) first, then compile the assembly code to object (.o), then link them.
But it seems above makefile code does not work. What is the correct code?

When asking questions, does not work is never very useful... if it worked you probably wouldn't be asking a question! :-) Instead you should always show the command you ran and the output you received (or at least the failing part of the output if it's long). Please cut and paste the actual text rather than paraphrasing messages. Also, including the version of the make program you're using (make --version) and the platform you're running on is often helpful.
Luckily this time we can figure out the problem without this information:
This:
$(ASM):%.c
gcc -S -o $# $<
where ASM is a.s b.s c.s, is not a pattern rule because the targets don't contain a pattern character %. That means the prerequisite %.c is not treated as a pattern, but as an actual file name, literally %.c which obviously doesn't exist.
Similarly, this:
all: %.o
has the same problem: all is a target, so this depends on the literal file named %.o which doesn't exist, and can't be created.
Also as a general rule every recipe that creates a target must create the actual target you told make it would, so this all rule is wrong because the target name is all but the recipe creates the target test.
Finally, it's a very bad idea to name your program test because test is a common UNIX program and a shell built-in, so if you run test it won't do the right thing (if you run ./test it will work).
You want to have all depend on the program you want to build, say mytest, and mytest should depend on the actual .o files:
all: mytest
mytest: $(SOURCE:.c=.o)
gcc -o $# $^
Next, you need to define a pattern rule that knows how to create an assembly file from a source file:
%.s : %.c
gcc -S -o $# $<
That, along with your other pattern rules, is all you need: make will figure it all out from that.
Finally, make has a built-in rule that tells it how to build object files directly from source files. It's best to get rid of this to force make to use your rules; add this to your makefile to delete it:
%.o : %.c

Related

Force make not to re-order pre-requisites in automatic variable expansion

Here a is my makefile (GNU make) to compile a small OCaml program:
SUFFIXES:=
OCAML=ocamlopt
LD=ocamlopt
OFLAGS=
.PHONY: all clean
all: playground
playground.cmx: playground.ml lstream.cmi
playground: lstream.cmx playground.cmx
%.cmi: %.ml
$(OCAML) $(OFLAGS) -c $<
%.cmx: %.ml
$(OCAML) $(OFLAGS) -c $<
%: %.cmx
$(LD) -o $# $^
playground uses functions from the Lstream module. In this case, the ocaml linker requires the files to link to be specified in order of dependency (eg: ocamlopt -o playground lstream.cmx playground.cmx).
Despite the fact that I defined the playground rule's dependencies in the right order,
make consistently re-orders them and executes ocamlopt -o playground playground.cmx lstream.cmx which causes a linker error.
Is there a way to enforce the correct behaviour ? I would like to avoid specifying the link command explicitely and let make infer it from the dependencies.
Implicit rules always force the pattern matching prerequisite to be first, regardless of the order in which they're defined elsewhere. This is almost always what you want, because in most rules the pattern matching prerequisite is special.
For example when compiling an object file the prerequisites consist of one source file and a bunch of header files; the source file is special and needs to be listed on the command line. Make ensures that for a pattern rule %.o : %.c (for example) the prerequisite matching %.c is first in the list, and so is assigned to the $< automatic variable, and it can be treated differently.
In any event the short answer is no, you cannot modify this behavior. An implicit rule % : %.cmx matching a target playground will always force the prerequisite playground.cmx to be listed first in the prerequisite list. The other prerequisites will maintain their order.
If you really need the prerequisites to maintain their order then I recommend using a static pattern rule:
TARGETS = playground
$(TARGETS) : % :
$(LD) -o $# $^
(you can also use a "match anything" pattern rule but this can be a real performance degrader). Here since you have no pattern in the prerequisite list, nothing will be reordered.

Makefile for using make as gcc

Is it possible to write universal Makefile which would get any target and act like a wrapper to gcc, but with parameters? For example, this means that
make 01.c
will have the same result as
g++ -o 01.out 01.c
make already has several "implicit rules" to do what you're trying.
For example, even with no makefile,
make 01.o
Will run:
c++ -c -o 01.o 01.cpp
If it finds a file called 01.cpp in your current directory. You can set the CXXFLAGS environment variable if you want to pass more flags. If you're really set on using g++ rather than the system compiler, you can set CXX=g++, too.
Yes - You using implicit rules.
Summat like (if memory serves me right)
.cpp.o:
$(CCC) $(CFLAGS) $< -o $#
Maybe in the set of default implicit rules
You can use a wildcard - %.
However, the thing specified on the commandline is the target, not the source - what you want, not what you have.
It looks like what you want is approximately:
%.out: %.c
g++ -o $# $<
This means: to make (something).out, first make sure you have (something).c, then run g++ -o (something).out (something).c
$# is always the target file, and $< is the first prerequisite.
You will need to run make 01.out, not make 01.c

How to use command line argument in GNU make?

For example, I have 10 source files named ex1.c, ex2.c, ex3.c....ex10.c and maybe more in the future.
Is it possible that I can use commandline argument as a variable in GNU Make so that when I want to compile ex1.c, I can type in make 1. If I want to compile ex10.c, I can type in make 10. And I don't need to add more lines to makefile when I add more sources like ex100.c later.
This doesn't strike me as a good idea, but yes, you can do it.
To build object files (e.g. ex3.o):
%: ex%.c
$(CC) -c $< -o ex$*.o
To build executables (e.g.ex3):
%: ex%.c
$(CC) $< -o ex$*

GNU Make Pattern Rule on MacOS X

I'm struggling with makefiles on OS X Lion. I'm trying to use % pattern rule to compile all my .c files into objects in current dir. I'm using rule:
%.o : %.c
$(CC) -c $(CFLAGS) $< -o $#
But make says that no targets. I know that % pattern it is feature of gMake but -v says that I've got GNU make installed. I've also tried old style:
.cpp.o:
gcc $^ -o $#
But it is do not working to. What I'm doing wrong? Thanks.
If that's your entire Makefile, then indeed, it contains no targets. Invoke it with make file.o or add a phony target all which lists the names of the files you want to have built. It could be as simple as
.PHONY: all
all: $(patsubst %.cpp,%.o,$(wildcard *.cpp))
What you have are pattern rules which specify "if you want to build a target of type *.o, here's how to do that" but no actual targets which specify "this is a file we want to build".
By the by, GNU Make already knows how to compile C files, so you don't really need to define that, unless you have a specific need to override the built-in pattern rule.

separate builds in separate directories

I'm sure this is a totally normal thing to do, but I can't figure out how to get make to do this.
I have a compiler that generates make dependencies of the usual form:
M/A.o : M/A.hs
M/B.o : M/A.o
So I write a rule to compile %.hs into %.o, add a rule to link the binary, include the dependencies file, and all is well. But I want to have several binary targets with different flags. E.g. I want build/test built with -DTESTING and build/profile built with -prof. So I need to keep the .o files in a separate tree, where they will be compiled with special flags.
The straightforward way I can think of would be to have dependencies that look something like this:
build/test/M/A.o : M/A.hs
build/test/M/B.o : build/test/M/A.o
build/profile/M/A.o : M/A.hs
... etc.
And then rules so that %.hs to build/test/%.o compiles with -DTESTING, etc. I think this would work, but it's clumsy, means preprocessing the deps file to add all that build/whatever/ prefix stuff, and would multiply its size by however many kinds of builds.
VPATH appears to be designed for this sort of thing and my idea was that I could set the VPATH and compiler flags depending on the target, and it almost works, but:
%.o: %.hs
#mkdir -p build/M
cp $< build/$#
VPATH = build
main: M/A.o M/B.o
cat $^ >$#
M/A.o : M/A.hs
M/B.o : M/B.hs
The first time the main target wants to run 'cat M/A.o M/B.o >main' which seems contrary to the gnu make documentation that says $^ should include the include the VPATH directory in which the dependency was found. Curiously, if I remove 'main' and make again, this time it uses the correct path. This is GNU make, 3.81.
What's going on here? Is there a better way to build with different flags? VPATH seems like a clumsy tool, surely there is a better way?
Make is working correctly. It tries cat M/A.o M/B.o >main the first time because it can't find the prerequisites it needs, but it knows a rule for M/A.o' andM/B.o(<em>not</em>build/M/A.o' and build/M/B.o) and expects that that is what the rule will produce. If you remove main and try again, it will find build/M/A.o' andbuild/M/B.o` via VPATH.
Let's modify this makefile in stages. First we change the VPATH so that it can find the .hs files (Make is good at using things there to build things here, not vise-versa, and that's what VPATH is good for), and change the rules slightly:
build/%.o: %.hs
cp $< $#
VPATH = M
main: build/A.o build/B.o
cat $^ > $#
Now for the different object directories.
build/test/%.o build/project/%.o: %.hs
cp $< $#
VPATH = M
test: build/test/A.o build/test/B.o
cat $^ > $#
project: build/project/A.o build/project/B.o
cat $^ > $#
Then we simplify those last two rules, so that it's easy to add more object files and binary targets:
OBJECTS = A.o B.o
test: $(addprefix build/test/,$(OBJECTS))
project: $(addprefix build/project/,$(OBJECTS))
test project:
cat $^ > $#
Now for the different compiler flags:
build/test/%.o: FLAGS += test_flags
build/project/%.o: FLAGS += proj_flags
build/test/%.o build/project/%.o: %.hs
#echo building $# from $^ using flags $(FLAGS)
cp $< $#
Finally the dependencies. This is a little tricky. Suppose you want the dependency B.o : A.hs to apply to however many object you have. This is one approach:
OBJECT_PATHS = build/test/ build/project/
# The following is from the included file generated by the compiler
$(addsuffix B.o,$(OBJECT_PATHS)) : A.hs
To generate lines like that, I'd pipe the raw lines (e.g. B.o: A.hs) through sed 's/\(.*\):\(.*\)/\1:\2/', and note that if you want to put this in a makefile command, don't forget to double the $ signs to preserve them for the shell.
I know that's a lot to absorb. Take it one step at a time and let us know how it works out.
If you haven't solved your problem by now or are experiencing further problems, best give the autotools (automake and autoconf) a chance. They'll quickly build you a Makefile that supports more configurable and flexible out-of-tree builds.

Resources