1

I am trying to build a shared library with one set of code, and everything works, except for this issue with my Makefile. Here's my (simplified) Makefile thus far:

OBJS = bar.o

libfoo.so:    OS = LINUX      # These don't seem to happen
libfoo.dll:   OS = WINDOWS

# Linux
ifeq ($(OS), LINUX)
CC = gcc
...

# Windows
else ifeq ($(OS), WINDOWS)
CC = i686-pc-mingw32-gcc
...
endif


all: libfoo.so libfoo.dll

libfoo.so: clean $(OBJS)
    ...

libfoo.dll: clean $(OBJS)
    ...


bar.o: bar_$(OS).c bar.h
    ...

So, when you type make libfoo.so, I expect it to set OS = LINUX first. Then, when it gets to bar.o (it is a dependency of libfoo) it should know which bar_$(OS).c to use. However, I get the error:

make: *** No rule to make target `bar_.c', needed by bar.o. Stop.

Which tells me that when it tries to make bar.o, $(OS) is not set. But shouldn't that be the first thing that happens when I try to make libfoo.so, and that rule is evaluated?

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328

3 Answers3

2

Target-specific variables are available in the body of the rule, not in its prerequisites. But even if you could get this to work, you'd be asking for trouble: if you build one library and then the other, there's no way for Make to know that the bar.o that was made for the first is wrong for the second and should not be used.

There are several ways to get the effect you want, but none is perfect. I'd suggest using two different object file names, like bar_unix.o and bar_windows.o.

Beta
  • 96,650
  • 16
  • 149
  • 150
  • "Target -specific variable " was the phrase I was looking for but didn't know. This makes sense now. Your separately-named o file solution is what I used yo get this working, and I guess I will stick with. Thanks! – Jonathon Reinhart Dec 07 '11 at 13:42
  • Turns out the way to really do this is with a recursive call to make.(which is more elegant in my situation, as I have a lot of variables to setup for the toolchain). – Jonathon Reinhart Dec 07 '11 at 21:22
0

If you want to set a target-specific variable, and then have that variable available outside the body of that rule, you can recursively call the Makefile, after exporting the variable:

OBJS ?= foo.o                    # Use ? so it isn't blown away on recursive call

libfoo.so: OS = LINUX
libfoo.so: OBJS += linux_only.o
libfoo.so:
    $(MAKE) -s build_libfoo_linux

build_libfoo_linux: $(OBJS)
    @echo "OS = $(OS)"           # Should print "OS = LINUX"

export OS                        # Can be anywhere

You have to remember to export the variables you want to "persist" after the recursive make call. And also, as shown above, if you append to any variables before the call, you'll want to make their initial assignment with ?= so they aren't set the second time.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
-1

You might want to detect the OS using uname and then conditionally compile. This explains

Community
  • 1
  • 1
ACC
  • 2,488
  • 6
  • 35
  • 61