0

I have the following simple problem in a Makefile:

%.o:: %.c
      gcc -o $@ -c $<

lib1.a: test.o
        ar -r $@ test.o
        rm *.o

lib2.a: test.o
        ar -r $@ test.o
        rm *.o

all: lib1.a lib2.a

make lib1.a or make lib2.a work properly. However, make all gives:

gcc -o test.o -c test.c
ar -r lib1.a test.o
rm *.o
ar -r lib2.a test.o
ar: test.o: No such file or directory
make: *** [lib2.a] Error 1

I need to do the rm *.o cause I want the object file to compile each time (in my real Makefile, I have a more complex use case where I compile with different flags).

How can I fix this problem? It seems that make compiles the object file only once.

I tried with .PHONY instead of doing the rm, but again, it compiles only once.

  • 1
    Creating the `.o` file *once* is well in line with how Make works, and shouldn't be a problem (in fact it's a good thing that it *doesn't* repeat that step, time-consumption-wise). What is odd is removing it immediately after running `ar`. Why do you do that? – Biffen Dec 01 '14 at 14:45
  • try using different names for each object file. – Iharob Al Asimi Dec 01 '14 at 14:47
  • 1
    Better yet, compile each set of .o files into separate directories – ikegami Dec 01 '14 at 14:52
  • Why do you have `lib1.a` and `lib2.a` containing the *same* object file? You should have a single `libmy.a` ! And you should use more variables in your `Makefile`, like [here](http://stackoverflow.com/a/16751650/841108) – Basile Starynkevitch Dec 01 '14 at 14:59
  • This is a simplified version of my actual Makefile. What I try to do is to create different libraries with one common object file and some others that are different. However, for some of the libraries I compile the common object file with different flags. I guess I could indeed try to create different object files as @iharob suggested. – Vasileios Trigonakis Dec 01 '14 at 15:10
  • @VasileiosTrigonakis As a rule of thumb, if you want to compile with different flags in *the same run* the results should go into different files. I'm still curious about the `rm`s, though... – Biffen Dec 01 '14 at 15:13
  • @Biffen Are you curious why it does not work, or why do I use them? If it's the latter, there isn't any particular reason apart from cleaning up and achieving the recompilation of the object files (with possibly different flags). – Vasileios Trigonakis Dec 01 '14 at 15:26
  • add another target that performs the two 'ar' statements then performs the 'rm' statement. the 'all' target then has a dependency of this new target. BTW: the 'all' target should be first so that it is executed when the user only enters 'make' with no parameter – user3629249 Dec 01 '14 at 17:27
  • @VasileiosTrigonakis The common way to do it is to have a separate `clean` target that does all forms of clean-up, and is used explicitly. That way you won't necessarily have to redo every step on each invocation. Do with that information what you like, it's just convention. – Biffen Dec 01 '14 at 20:30

2 Answers2

2

Your makefile is a bit against the make logic, this is why the result is not what you expect:

  • Here you define two targets (lib1.a and lib2.a) with a common dependency: test.o.
  • Then you define the rule all (which, by the way, should be .PHONY but this isn't a problem here) that depends on lib1.a and lib2.a.

So, in order to "do" all, make have to build lib1.a and lib2.a. They both depend on test.o, so make builds test.o once, then build lib1.a and lib2.a, expecting that the recipes you defined will just build those files, and nothing more.

The problem is that you delete test.o in the recipe for lib1.a and lib2.a, although this action is not needed to build them, this is something you want to do when cleaning, not building.

There are two solutions:

  1. Move the deletion operation in a rule that is meant to do that (a .PHONY rule named clean for example).
  2. The use of intermediate targets which will be deleted when they're not needed anymore. In fact, you can achieve that without even thinking about intermediate targets if you simply delete the first rule of your makefile (the %.o:: %.c one), because make already has an implicit rule that does that using intermediate targets.
Dettorer
  • 1,247
  • 1
  • 8
  • 26
0

Make is a rule-based system. Rules are declarative: you declare what you want built from what, you don't specify the order in which this happens (unless you can't avoid it). So a good Makefile is declarative: all results are declared like in a declarative programming language. They are like final variables in Java: you bind them to a value, you don't reassign them to a different value afterwards.

Make is also file-based: its "variables", targets and prerequisites are files.

So if you want to build two different things, don't call them by the same name! If you want two different test.o files, call them differently. The problem will go away without you needing to try and convince make that it should be like an imperative programming language, which it was specifically designed not to be. If you want an imperative build specification, use a shell script.

reinierpost
  • 8,425
  • 1
  • 38
  • 70