tags:

views:

56

answers:

3

I don't know how to execute a command stored as a variable or how to use ifeq inside of a target, so I have a very redundant Makefile at the moment!

Ideally I'd like to have just one target (all) which would run the stored command on Mac and run it twice on Linux, once with -m32 and once with -m64.

all:
    echo PLEASE SELECT OS, e.g. make linux
    exit 1

mac:
     gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)

linux:
    gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64) -m64
    gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES) -m32

UPDATE: This is what I ended up with, after reading the various suggestsions. (Yes I know I should use autoconf . . .) Thanks everyone for your help!

ifeq($(PLATFORM), Linux)
    COMMON = -pthread -fPIC
    PLATFORM_CFLAGS = $(COMMON) -m32
    PLATFORM_CFLAGS64 = $(COMMON) -m64
endif

ifeq ($(PLATFORM), Darwin)
    PLATFORM_CFLAGS = -arch i386 -arch ppc -arch x86_64 -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk
endif

all: $(PLATFORM)_all

Darwin_all:
     mkdir -p ../../../../tmp
     gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)

Linux_all: Darwin_all
     gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS64) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64)
+2  A: 

This is pretty simple, but you should be able to adapt it to more complicated things by changing the shell command that you run.

PLATFORM := $(shell uname)

all:$(PLATFORM)

Darwin:
    echo Darwin

Linux:
    echo Linux
Ivan Andrus
thanks for your help Ivan. I've used this to eliminate some of the redundancy of the script, but I still am not sure how to consolidate the common parts before -m32 or -m64. Is there any way to run a variable that you've stored?
Yuvi Masory
+2  A: 

You make macros do most of the work, noting that you should use $(CC) rather than gcc.

BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32  = $(BUILD_NAME)
TARGET_32     = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64     = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32       = $(LIBRARIES)
LIBS_64       = $(LIBRARIES64)
OPTS_32       = -m32
OPTS_64       = -m64

# We could do some fancy stuff here...
# Except that we will remove the commands momentarily
all:
    echo PLEASE SELECT OS, e.g. make linux
    exit 1

# Note that without a qualifier
# - MacOS X 10.5.x will build 32-bit
# - MacOS X 10.6.x will build 64-bit
# But why not build both anyway?
mac:
    $(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
    $(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)

linux:
    $(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
    $(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)

Oh, and look, the commands are the same for Linux and MacOS X now...so we can do:

BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32  = $(BUILD_NAME)
TARGET_32     = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64     = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32       = $(LIBRARIES)
LIBS_64       = $(LIBRARIES64)
OPTS_32       = -m32
OPTS_64       = -m64

all:
    $(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
    $(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)

Gosh, it is hard work writing $(XXX) instead of ${XXX} as I normally do in my makefiles.

Basically, we apply DRY (Don't Repeat Yourself) by making names boringly systematic. Makefiles should not be exciting.

If you still want to have a difference between your platforms, then you can do something along the lines suggested by Ivan Andrus. GNU Make allows you to evaluate shell commands, so:

BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32  = $(BUILD_NAME)
TARGET_32     = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64     = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32       = $(LIBRARIES)
LIBS_64       = $(LIBRARIES64)
OPTS_32       = -m32
OPTS_64       = -m64

all:  $(shell uname)

Linux:
    $(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)
    $(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)

Darwin:
    $(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32)

If you feel you can't rely on GNU Make, then:

BUILD_COMMAND = $(CC) $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS)
BUILD_NAME32  = $(BUILD_NAME)
TARGET_32     = $(BUILD_DIR)$(BUILD_NAME32)
TARGET_64     = $(BUILD_DIR)$(BUILD_NAME64)
LIBS_32       = $(LIBRARIES)
LIBS_64       = $(LIBRARIES64)
OPTS_32       = -m32
OPTS_64       = -m64
BUILD_32      = use_32_bit
BUILD_64      = use_64_bit
BUILD_TYPE    = $(BUILD_32) $(BUILD_64)

.PHONEY: $(BUILD_32) $(BUILD_64)

all:  $(BUILD_TYPE)

use_64_bit:
    $(BUILD_COMMAND) -o $(TARGET_64) $(SOURCE) $(LIBS_64) $(OPTS_64)

use_32_bit:
    $(BUILD_COMMAND) -o $(TARGET_32) $(SOURCE) $(LIBS_32) $(OPTS_32)

By default this will compile both 32-bit and 64-bit versions. If you want 32-bit only or 64-bit only, run the appropriate one of these two:

make BUILD_TYPE=use_32_bit
make BUILD_TYPE=use_64_bit
Jonathan Leffler
Wow thanks for all your help. Just btw, the PLATFORM_CLFLAGS for Mac already had -arch for PPC, Intel 32, Intel 64, which is why I wrote it that way. Thanks again.
Yuvi Masory
+1  A: 

You have some good advice there (probe the platform, use variables) but you should also be aware that you're running very close to the point where it is better to stop thinking in terms of supporting platforms and instead in terms of describing features that you require for your software and using autoconf (and family) to discover what is actually present.

Mind you, if it is a GUI app then you'll probably have so many differences between the OSX code and the Linux/X11 code that detecting by platform is reasonable. It's just rare that you need to do that for anything that's command-line oriented, as OSX looks a lot like plain old Unix then.

Donal Fellows