(this FAQ should cover Borland and GNU MAKE, maybe others) ================================================================ "Why should I use MAKE? My IDE has a project manager." ================================================================ - If you change compilers, your old project files become useless. Well-written makefiles (and well-written versions of Make) are more portable. xxx - other reasons? ================================================================ "Is there a 'standard' MAKE?" ================================================================ xxx - I'm not sure. POSIX? ================================================================ "Show me an example makefile" ================================================================ Here is a working DJGPP makefile, with annotation: # As you may have guessed, comments in makefiles start with # # so the line below has been commented out. (See: "Should the # makefile itself be a dependent?") #MAKEFILE=dj.mak # Define a macro with name "DEBUG" and value "-g -Wall". DEBUG =-g -Wall # After defining a macro, you'll want to use it. Do this by # surrounding the macro name with ( and ) and prefixing # it with $. This declaration sets CFLAGS to "-g -Wall -O2" CFLAGS =$(DEBUG) -O2 NFLAGS =-f coff LFLAGS =$(DEBUG) FAR =main.o dj.o font.o lf32_8.o NEAR =main.o dj2.o font.o ln_8.o # The line below has a colon in it, so it's a rule or dependency # or both (a dependency, in this case). The first explicit # rule or dependency of the makefile is the default target; # the action that MAKE takes when you just type "make" with # nothing after it. Here, MAKE will attempt to build the # files "near.exe" and "far.exe". # # The rule to build all targets has the traditional name # "all". If the default target is not "all", then the # traditional name "dummy" is used for the default target. all: near.exe far.exe # Two "implicit rules". These tell MAKE how to convert ".c" # files into ".o" files (i.e. how to compile), and how to # convert ".asm" files into ".o" files (i.e. how to assemble). # # The whitespace before "gcc" and "nasm" MUST be a tab # (see: "What does 'missing separator' mean?"). .c.o: gcc $(CFLAGS) -c -o$@ $< .asm.o: nasm $(NFLAGS) -o$@ $< # An "explicit rule". This tells MAKE how to build the # executable file "far.exe" from the object files listed # in $(FAR). # # Note $(MAKEFILE) in the top line but not the bottom. The # makefile is not incorporated into "far.exe", but it is # a dependent, i.e. "far.exe" should be re-built if the file # named by $(MAKEFILE) changes. far.exe: $(FAR) $(MAKEFILE) gcc $(LFLAGS) -o$@ $(FAR) near.exe: $(NEAR) $(MAKEFILE) gcc $(LFLAGS) -o$@ $(NEAR) # This is a dependency. It relies on an implicit rule defined # elsewhere (in this case, the ".c.o" rule). It translates as # "If any of the files main.c, defs.h, or dj.mak are # changed, then main.o should be re-compiled." main.o: main.c defs.h $(MAKEFILE) # "dj2.o" and "dj.o" are both built from file "dj.c". The C # macro "NEARPTR" is defined when compiling "dj2.o". This is # not the default behavior of the ".c.o" implicit rule above, # so "dj2.o" needs an explicit rule. # # "defs.h" is #include'd by "dj.c". It is treated the same # way as $(MAKEFILE): though not mentioned on the "gcc" # command line, it is a dependent. dj.o: dj.c defs.h $(MAKEFILE) dj2.o: dj.c defs.h $(MAKEFILE) gcc -DNEARPTR=1 $(CFLAGS) -c -o$@ dj.c font.o: font.c defs.h $(MAKEFILE) lf32_8.o:lf32_8.c defs.h $(MAKEFILE) depth8.c ln_8.o: ln_8.c defs.h $(MAKEFILE) depth8.c # "clean" is the traditional name of the target which deletes # temporary and/or intermediate files. You invoke this target # by typing "make clean". clean: del *.o del *.obj del *.exe ================================================================ "What is all that punctuation? Is MAKE cursing back at me?" ================================================================ The two-character codes made of punctuation and starting with $ are "automatic variables" (GNU Make terminology). Here are some common ones: C:\PROJ\FOO.OUT : C:\PROJ\FOO.IN Borland MAKE: Variable Implicit rule Explicit rule $* path + root path + root C:\PROJ\FOO C:\PROJ\FOO $? path + infile path + infile C:\PROJ\FOO.IN C:\PROJ\FOO.IN $@ path + outfile path + outfile C:\PROJ\FOO.OUT C:\PROJ\FOO.OUT $< path + infile path + outfile C:\PROJ\FOO.IN C:\PROJ\FOO.OUT $& root root FOO FOO $. infile outfile FOO.IN FOO.OUT $: path (directory) path (directory) C:\PROJ C:\PROJ GNU MAKE: Variable Implicit rule Explicit rule $* path + root path + root C:\PROJ\FOO C:\PROJ\FOO $? path + infile path + infile C:\PROJ\FOO.IN C:\PROJ\FOO.IN $@ path + outfile path + outfile C:\PROJ\FOO.OUT C:\PROJ\FOO.OUT $< path + infile path + infile C:\PROJ\FOO.IN C:\PROJ\FOO.IN Watcom WMAKE: xxx ================================================================ "Can I put more than one command in a rule?" ================================================================ Yes. Here is an example explicit rule with three commands: start32.obj: start32.asm $(MAKEFILE) nasm -f win32 -ofoo start32.asm coff2omf foo start32.obj del foo The rule ends with a blank line. Remember that each of the three command lines here must be preceded with a tab, not spaces. ================================================================ "The lines in my makefile are too long to read!" ================================================================ You may end the line with \ as a "continuation character". (See also: "I think the command line is too long.") Example: STRING =string/stricmp.o string/strnset.o string/memcmp.o \ string/strcat.o string/strnicmp.o string/strncat.o \ string/strchr.o string/memicmp.o string/strcpy.o \ string/strlwr.o string/strncpy.o string/strcmp.o \ string/strupr.o string/strncmp.o string/strlen.o \ string/strstr.o string/strset.o string/memmove.o \ string/memset.o string/memset16.o string/memset32.o \ string/memchr.o string/memcpy.o This is, syntactically, a single line. If you need \ at the end of a line (e.g. as a DOS path separator) then escape the \ with a second \ # specify location of reentrant startup code and libs OBJDIR =g:\locate\\ LIBDIR =g:\locate\\ ================================================================ "What does 'missing separator' mean?" ================================================================ GNU MAKE produces this error when the first command after your implicit or explicit rule is delimited with spaces instead of a tab. (I believe the use of tab as a delimiter is a requirement of the POSIX spec. Yes, this is stupid.) You should avoid using DOS EDIT to create or edit makefiles, as it often expands tabs as spaces. ================================================================ "What is .SUFFIXES: for?" ================================================================ You need one of the following to build a file: - Explicit rule - Implicit rule + dependency In the second case, Make also needs to know about filename extensions (suffixes). Some are built-in, others are not. In general, when you use implicit rule + dependency to build a file, and the source file has an "unusual" extension, you should use .SUFFIXES. Or, if you're feeling lazy or paranoid, just tell Make about all the filename extensions you've known: .SUFFIXES: .c .cpp .asm .nsm .s .i .o .obj .a .lib .SUFFIXES: .elf .cof .exe .com .bin xxx - not sure about this ================================================================ "Can I have multiple dependency lines for the same file?" ================================================================ xxx - I don't know. dj.o: dj.c dj.o: defs.h dj.o: $(MAKEFILE) ================================================================ "Can I have a dependency in an implicit rule?" ================================================================ xxx - I don't know. # recompile all C files if the makefile changes??? .c.o: $(MAKEFILE) gcc $(CFLAGS) -c -o$@ $< ================================================================ "Can I have multiple files on the left side of a dependency?" ================================================================ This works: $(OBJS): defs.h xxx - but I don't know about this: # rebuild all object files if the makefile changes *.o: $(MAKEFILE) ================================================================ "Can I chain dependencies?" ================================================================ xxx - I don't think so. dj.o: dj.c defs.h $(MAKEFILE) depth8.c cppdefs.h: defs.h # rebuild win.o if defs.h changes??? win.o: win.cpp cppdefs.h $(MAKEFILE) ================================================================ "Can I 'add on' to an implicit rule?" ================================================================ xxx - I don't know. .c.o: gcc $(CFLAGS) -c -o$@ $< # normal build foo.o: foo.c # compile object file then strip it -- xxx -- doesn't work bar.o: bar.c strip $@ ================================================================ "MAKE stops when I say 'make clean' and the delete operation fails because the file has already been deleted" ================================================================ Prefix the name of the delete command with a dash. This will cause MAKE to assume the command is always successful: clean: -rm krnl/*.o -rm boot/*.bin -rm lib/*.a lib/*.o ================================================================ "My IDE handles dependencies automatically; does MAKE?" ================================================================ It might. The GNU C preprocessor can examine C files for #include statements, and generate an appropriate MAKE dependency: C:\TMP>cpp -MM ln_8.c ln_8.o: ln_8.c defs.h depth8.c These automatically-generated dependencies could be directed into files, and the files include'd in the makefile. CSRC := $(wildcard *.c) DEPS := $(CSRC:.c=.d) # how to use GCC to calculate dependencies CDEP =gcc -M -nostdinc -I$(INCDIR) $< >$@ %.d : %.c $(CDEP) # now, include those dependencies in this makefile: ifneq ($(MAKECMDGOALS),clean) -include $(DEPS) endif xxx - exclude dependencies for 'clean' target, or else automatic dependency (*.d) files will be built when you say 'make clean' ================================================================ "Should the makefile itself be a dependent?" ================================================================ Probably. If you change command-line options in the makefile (e.g. turn source-level debugging information on or off, change the memory model, or change the optimization level), then everything should be rebuilt. This can be tedious when you make large-scale changes in your source code, or when debugging the makefile itself. You should do something like this: #MAKEDEP=makefile main.o: main.c defs.h $(MAKEDEP) Here, the declaration of MAKEDEP is commented out i.e. $(MAKEDEP) is an empty string, and main.o does NOT depend on it. Once your code is relatively stable and the makefile is debugged, the definition of MAKEDEP should be un-commented. ================================================================ "Can I use $< in an explicit rule?" ================================================================ This is probably not a good idea. GNU MAKE appears to expand this as the first file name in the dependency list, but other MAKEs may not behave this way. NO: fun.exe: sex.o drugs.h rock.h roll.h $(MAKEFILE) gcc $(LFLAGS) -o$@ $< krnl.exe: load.o krnl.o lib.o config.h $(MAKEFILE) gcc $(LFLAGS) -o$@ $< # links only load.o YES: fun.exe: sex.o drugs.h rock.h roll.h $(MAKEFILE) gcc $(LFLAGS) -o$@ sex.o OBJS=load.o krnl.o lib.o krnl.exe: $(OBJS) config.h $(MAKEFILE) gcc $(LFLAGS) -o$@ $(OBJS) ================================================================ (DOS) "I think the command line is too long." ================================================================ This is quite possible with DOS. There are several work-arounds. 1. DJGPP supports several methods of dealing with this; consult the DJGPP FAQ if you are using that environment. 2. "Response files". The better-quality DOS tools support this method. The long command lines are written to a temporary file, then the compiler, linker, or other tool reads the command lines from the file. Example: to invoke a long Turbo Link command line from within Borland MAKE, you can do this: main.exe: $(OBJS) $(MAKEFILE) tlink /x $(LFLAGS) @&&! c0$(MODEL).obj $(OBJS) $. # no map file (/x option) c$(MODEL).lib ! The syntax shown here is specific to Borland MAKE. Check the documentation for your MAKE to see if it supports response files, and what their format should be. 3. Chose shorter filenames, and/or shorter filename extensions. With care, you can create a Borland makefile that uses the extension ".o" instead of ".obj" for object files. 4. Use wildcards: gcc $(LFLAGS) -o foo.exe *.o ================================================================ "What do these messages mean?" 'Load error: can't switch mode' 'DOS/16M error: [32] DPMI host error' ================================================================ These are error messages from "DOS extenders"; programs that let you run 32-bit code under DOS. These programs are not always well-behaved. Starting with Turbo/Borland C 3.0, Borland's DOS tools use a 16-bit DOS extender which is incompatible with the 32-bit DOS extenders used by some other DOS compilers. If you want to use Borland's MAKE with a non-Borland compiler, use real-mode MAKER.EXE instead of MAKE.EXE ================================================================ "MAKE is trying to run 'rm'. This is not a DOS command!" "I told MAKE to use '-O2' with GCC, but it's not." ================================================================ Some versions of MAKE, when faced with an incomplete makefile, try to be helpful by using "built-in" rules. These are generally NOT helpful. Debug your makefile. GNU MAKE lets you disable the built-in rules with the "-r" or "--no-builtin-rules" options. For Borland make, find and delete (or rename) the file BUILTINS.MAK, usually in the same directory as MAKE.EXE ================================================================ "'File format not recognized, treating as linker script'" "'linker input file unused since linking not done'" ================================================================ Some compilers are collections of tools, with a "driver" program that invokes the others as needed. GNU C falls into this category. "gcc" is merely the driver; the actual work is done by "cpp" (preprocessor), "cc1" (the compiler proper), "as" (assembler), and "ld" (linker). Sometimes the driver has to guess at what you are trying to do. It does this by making assumptions about file contents based on the extension of the filename. Unusual filename extensions can confuse it. Consider: what is to be done here? gcc -o homer.foo homer.bar MAKE will echo commands to the screen as it executes them. Study this output to see if your makefile is buggy. Are you trying to assemble a makefile? Link a .h file? ================================================================ "'Error: Undefined symbol FIWRQQ in module foo.cpp'" "'Error: Undefined symbol FIDRQQ in module foo.cpp'" "'Error: Undefined symbol N_FTOL@ in module foo.cpp'" ================================================================ Looks like you're trying to compile a program under Turbo or Borland C; a program that uses floating-point math. You are probably forgetting to link in the floating-point libraries. One is named "maths.lib", "mathl.lib", "mathc.lib", etc. depending on the memory model. The other is either "fp87.lib" if your target system has an 80x87 math coprocessor, or "emu.lib" if the target system has no 80x87. OBJS =c0$(MODEL).obj foo.o # emulated or hardware floating point? LIBS =c$(MODEL).lib math$(MODEL).lib emu.lib #LIBS =c$(MODEL).lib math$(MODEL).lib fp87.lib foo.exe: $(OBJS) $(MAKEFILE) tlink $(LFLAGS) $(OBJS), $.,,$(LIBS) ================================================================ "Are there any alternatives to MAKE?" ================================================================ Lots of them. But if you think Make sucks, wait until you see the alternatives: http://www.linuxlinks.com/Software/Programming/Development/Tools/Make_Tools/index.shtml http://makepp.sourceforge.net/ http://www.trolltech.com/developer/download/tmake.html http://www.tmk-site.org/ http://www.canb.auug.org.au/~millerp/cook/cook.html http://www.gnu.org/software/cons/ http://www.scons.org/ http://jakarta.apache.org/ant/ ftp://ftp.cs.colorado.edu/pub/distribs/odin/ http://buildtool.sourceforge.net/ http://www.perforce.com/jam/jam.html http://www.acm.uiuc.edu/sigops/rsrc/depend.html "now a 'make depend' will calculate dependancies [automatically]"