tags:

views:

204

answers:

2

Hello,

I am compiling a demo project.

The project is written for windows and linux. I have written a Makefile. However, I am not sure how to specify the platform the compiler will be compiling on.

I will be compiling on Linux.

In my source file I have this:

#if defined(WIN32)
#include ...
#include ...
#elif defined(LINUX)
#include ...
#include ..
#else
#error "OS not supported"
#endif

My simple Makefile is this. And when I compile I get the error "OS not supported".

How can I add the directive so that it will compile with the #elif defined(LINUX).

LIBS_PATH = -L/usr/norton/lib
INC_PATH = -I/usr/norton/include

LIBS = -lntr

app: *.cpp *.h Makefile

    g++ $(LIBS_PATH) $(INC_PATH) *.cpp -o app

Many thanks for any suggestions,

+1  A: 

Decide which is going to be your default platform - say LINUX.

LIBS_PATH = -L/usr/norton/lib
INC_PATH  = -I/usr/norton/include
LIBS      = -lntr
PLATFORM  = -DLINUX
CXX       = g++

app: *.cpp *.h Makefile
    ${CXX} ${CFLAGS} ${PLATFORM} ${INC_PATH} *.cpp -o $@ ${LIBS_PATH} ${LIBS}

You can use round brackets in place of braces. This uses a macro for the C++ compiler, allows you to add other flags via CFLAGS (though that is also usually set by 'make'), and adds a platform, the include path, the library path and the actual library to the compile line.

Note that your rule enforces a complete recompilation of everything every time anything changes. This is 'safe' but not necessarily efficient. Note that wild-cards are dangerous too - more so for the source than the headers. You may include that backup copy of a file in the build (old-reader.cpp - you only wanted reader.cpp in there really). More conventionally, you list the object files needed for the program so that each object file can be individually rebuilt when needed, and the results linked together. If you get your dependencies correct (a moderately big 'if'), then there's no problem. If you get them wrong, you can end up with inconsistent programs.

However, if the difference is between a 5 second recompile and a 5 minute recompile, you should probably take the 5 minute recompilation (as shown) and answer another SO question while waiting.

To compile on Linux (64-bit):

make CFLAGS="-m64"

To compile on Linux (32-bit):

make CFLAGS="-m32"

To compile on Windows 64:

make PLATFORM=-DWIN64

To compile on Windows 32:

make PLATFORM=-DWIN32

Etc.

Jonathan Leffler
Thanks that worked great. I am just wondering what does the $@ mean? Thanks.
robUK
It's the file name of the target of the rule. See the make manual at http://web.mit.edu/gnu/doc/html/make_10.html#SEC94
Gonzalo
As Gonzalo said, it is the name of the target; in this context, that means 'app', but it means you can rename it to 'killer-app' and you don't have to change the compiler command line - the name changes automatically. Indeed, you might notice that the only non-macros on that command line are the '*.cpp' and the '-o' option. The latter is mandated by POSIX - so it is pretty safe; the former should be '${OBJECTS}' or thereabouts. As a rule, there should be very few non-macros on the command line, because you can change macros easily but literal text can't be changed.
Jonathan Leffler
+1  A: 

You can add -DLINUX=1 when compiling.

Also, if you run:

echo "" | cpp -dD

You can see the list of default #define when compiling. In linux, there will always be a:

#define __linux__ 1

in the output. So if you change your LINUX by the above #define, you don't need to do anything special. Ie:

...
#elif defined(__linux__)
...

As for the Makefile itself, I would do something like:

CXX=g++
CPPFLAGS = -I/usr/norton/include
LDFLAGS = -L/usr/norton/lib -lntr
OBJ_FILES = one.o two.o

app: $(OBJ_FILES) Makefile

one.o: one.cpp one.h

two.o: two.cpp two.h

So the implicit rules are used.

Gonzalo
Yeah, but how does he do that in the given infrastructure?
Jonathan Leffler
I edited my answer with another option that will work too.
Gonzalo