views:

182

answers:

3

I'm working to improve the long languishing Linux build process for Bitfighter, and am having problems with make. My process is actually quite simple, and since make is (nearly) universal, I want to stick with it if I can.

Below I've attached my current Makefile, which works, but clumsily so. I'm looking for ways to improve it, and have three specific questions at this point.

First, the project can be built with several options. Let's take debug and dedicated for this example. The dedicated option will exclude all UI code, and create a more efficient binary good for hosting (but not playing) games. The debug option adds a flag to the compiler that activates debugging code. One might want to build the game with either, both, or neither of these options.

So the question is, how do I make this work? As you can see from the comments in the makefile below, debugging is enabled by setting DFLAGS=-DTNL_DEBUG. I'd like to have the user type

make dedicated debug

rather than

make dedicated DFLAGS=-DTNL_DEBUG

How can I rewrite my makefile so that this will work?

Secondly, when I install the lualibs package on different versions of Linux, I get different libraries. For example, on Ubuntu, when I install the lualib package with apt-get, I get lua5.1.a in my /usr/lib folder. On Centos, when I install the same thing with yum, I end up with liblua.a in my /usr/lib folder. How can I get make to figure out which library I've got, and link that in? Obviously the -l directive is not smart enough for that. I'd like the user to not have to worry about where Lua ends up when it gets installed, and for the makefile to just work.

Finally, is there any way to get make to detect whether certain required packages (freeglut, for example) have not been installed, and either install them automatically or at least alert the user to the fact they need to get them installed (as opposed to simply terminating with a cryptic error message)?

Thanks!!

Here is my Makefile.

# Bitfighter Makefile
#######################################
# 
# Configuration
#
# 
# Some installs of lua call the lua library by different names, and you 
# may need to override the default lua library path.  For the ServerHitch  
# CENTOS installs, for example, you will need to specify the lua library 
# on the make command line:
#     LUALIB=/usr/lib/liblua.a
#
#
# To compile Bitfighter with debugging enabled, specify
#     DFLAGS=-DTNL_DEBUG
# on the make command line
#
#
# Building with make on Windows is still highly experimental. You will 
# probably need to add
#     WFLAGS="-DWIN32 -D_STDCALL_SUPPORTED" THREADLIB= GLUT=-lglut32 INPUT=winJoystick.o
# to the make command line to have any hope of getting it to work!  :-)
#
#
#######################################

CC=g++ -g -I../tnl -I../glut -I../openal -DTNL_ENABLE_LOGGING 
THREADLIB= -lpthread
GLUT=-lGL -lGLU -lglut
INPUT=linuxInput.o 

OBJECTS_ZAP=\
   CTFGame.o\

...many more...

   BotNavMeshZone.o\
   ../master/masterInterface.o\

CFLAGS=
DFLAGS=
EXEFILE=bitfighter
OPENAL=../openal/linux/libopenal.a
LUALIB=-llua5.1
WFLAGS=

.c.o:
   $(CC) $(DFLAGS) $(WFLAGS) -c $(CFLAGS) $<

.cpp.o : 
   $(CC) $(DFLAGS) $(WFLAGS) -c $(CFLAGS) $<


default: ../exe/bitfighter

bitfighter: ../exe/bitfighter

dedicated: CFLAGS=-DZAP_DEDICATED 
dedicated: GLUT=
dedicated: OPENAL=
dedicated: EXEFILE=bitfighterd
dedicated: ../exe/bitfighter


../exe/bitfighter: $(OBJECTS_ZAP)
   $(CC) -o ../exe/$(EXEFILE) $(OBJECTS_ZAP) ../tnl/libtnl.a \
       ../libtomcrypt/libtomcrypt.a \
       $(OPENAL) $(GLUT) $(THREADLIB) $(LUALIB) -lstdc++  -lm

../master/masterInterface.o:
   make -C ../master

clean:
   rm -f $(OBJECTS_ZAP) ../exe/bitfighter ../exe/bitfightered

cleano:
   rm -f $(OBJECTS_ZAP)
+2  A: 

pkgconfig will answer a lot of your questions.

To detect if lua is installed, check the return value of

pkg-config --exists lua

(which should return 0 if lua is installed) Use

pkg-config --cflags --libs lua

to see what should be passed in the command line to compile with lua on the system. (You'll probably want to add this to CFLAGS).

For the first, Make will not help you. Commands you give it specify targets, not options. You'll want to use something like autoconf to generate a ./configure script. From this, your user could type ./configure --enable-debug --enable-dedicated (or explicitly turn these off with --disable-*). As long as your dependencies use pkg-config (which most *nix programs do, unsure about freeglut), then it is simple to use the PKG_CHECK_MODULES macro in autoconf to give friendly error messages and get the correct command line arguments for the libraries.

Since it looks like you want to build with Windows, you may want to look into using CMake instead to generate the Makefile specific to the system used and the configuration desired. The output does look better and it should still work with pkg-config.

sargas
Yes this will help detect thinkgs. But it does not provide the framework for building the appropriate makefiles.
Martin York
Sorry if its not clear, but autoconf will do this with the PKG_CHECK_MODULES and related macros
sargas
+3  A: 

Raw make doesn't really support any of these uses. make considers targets passed in on the command line to be different programs to be built, or different actions to take, and it has no concept of using two targets passed in to switch independent options for a single build. make also doesn't have any built in support for checking for versions of packages installed.

It's a bit of a steep learning curve, but the most common solution for all of these problems is to use the GNU autotools toolchain (Autoconf and Automake, specifically). These tools have been written to help write portable, configurable build systems, that can probe the system for libraries in various locations, and generate Makefiles based on configuration options and the user's system.

If you have ever run ./configure; make; make install, you have probably used a configure script generated with Autoconf and Automake.

The Wikipedia article provides a bit of an overview, and the Automake manual provides a tutorial introducing the toolchain.

For your usage, what you would probably want to do is create a configure using Autoconf that takes options like --enable-debug and --enable-dedicated, to set options for generating your Makefile. You could then port your Makefile to Automake, or you could simply turn your Makefile into a Makefile.in with a few variables that Autoconf will fill in when generating the Makefile.

While the GNU Autotools system is very complete, and supports a lot of platforms, it is a bit baroque. There are some alternative build systems that support some similar auto-configuration behavior, like CMake and SCons, that might be worth looking into if Autotools feels like too much.

For the specific task of detecting certain libraries, and finding the options you need to link to them, pkg-config can be used; however, not all libraries install pkg-config definitions, and not all systems even have pkg-config installed, so it's not a universal solution, but can be a nice quick and easy way to get something building without too much messing with options in the cases in which it does work.

Brian Campbell
I think that for my situation, rather than get into the complexity of autotools, I'll create a simple bash script that figures out what flags to pass to make. If my build were any more complex than it is, then I would take your suggestion. It just seems overkill for what I need at this point.
Watusimoto
A: 

I'll start (as I always do) by recommending CMake. It'll generate makefiles for you from a higher level of abstraction. If you want to build differently configured binaries you would let CMake generate to different build trees with different parameters (one for "debug" and one for "dedicated"). This will give you two separate sets of Makefiles, one which builds the debug binary and one which builds the dedicated binary, all from the same set of sources. (CMake is available in binary form for most commonly used platforms today. Linux, Solaris, Windows, OSX, etc, and can be built from sources on a number of other platforms as well.)

CMake also has support for detecting the presence of external libraries, although I have very little experience of using that.

If you want to keep using GMake, I'd solve the "debug vs. dedicated" problem by recursively invoking make, like this:

default: debug

debug:
        $(MAKE) all FLAGS=....

dedicated:
        $(MAKE) all FLAGS=...
JesperE
Thanks for the suggestion. This would not seem to handle the "dedicated debug" case very well. I will, however, look into CMake to see if it gives me what I need.
Watusimoto
CMake is quite flexible; there is often several ways to approach a problem like this.
JesperE