This page was last updated on March 13th, 2020(UTC) and it is currently May 30th, 2023(UTC).
That means this page is 3 years, 78 days, 4 hours, 6 minutes and 43 seconds old. Please keep that in mind.
29 - Near Universal Makefile
The following could potentially be made simpler, but I'm, to be 100% honest, not that familiar with the intricacies of the makefile langauge. The things you find while googling seem to suggest that neither is anyone else: you'll see people specifying compilers when make seems to be doing a good job of that itself. It will apparently tries to guess the best way based on the recipies. I assume it either picks this up from "depencies" or something else. If this goes over you head, that's fine, I don't expect many to pick up on it right away. At the very least understand the last paragraph, but do try to go though this page, anyway, instead of being lazy and skipping it. MAKE is a powerful tool that will save you alot of time in trouble in the long run, and you'll be using it no matter what era you're in. A simple makefile (which we won't be using) would look something like this (save it as "makeflile", btw, as make will assume that filename by default): all:
g++ main.S -o main.exe
run:
make all
main.exe
Until now, that's how I've been writing my makefiles. I decided to learn how to make a better makefile for this tutorial, because you deserve better. Unfortunately, this also means you're not likely to understand what's going on, either, but I'm going to try my best.
#Sources
ASRC = vtools.S
CSRC =
CPPSRC =
CFLAGS =
CPPFLAGS = -fno-rtti
#Object file management
AOBJ = ${ASRC:.S=.o}
COBJ = ${CSRC:.c=.o}
CPPOBJ = ${CPPSRC:.cpp=.o}
OBJ = ${AOBJ} ${COBJ} ${CPPOBJ}
EOBJ = c:/djgpp/lib/crt0.o -Lc:/djgpp/bin/../lib/gcc/djgpp/9 -Lc:/djgpp/bin/../lib/gcc -Lc:/djgpp/lib -Lc:/djgpp/bin/../lib/gcc/djgpp/9/../../.. -Lc:/djgpp/lib -lgcc -lc -lgcc
#Recipies
.PHONY: all clean release run
all: main.exe
strip main.exe
main.exe: ${OBJ}
ld ${OBJ} ${EOBJ} -o main.exe
#Normally, you'd be calling gcc as it's not as slow on other systems. Here we need to invoke LD directly to save time.
#Release build may produce slightly larger EXE than the linked version with the same optimization flags in exchange for unraveling certain tasks, but the code runs faster.
release:
gcc rmain.cpp ${ASRC} -o release.exe -s -O9 -fno-rtti
run: all
main.exe
clean:
del *.o
del *.exe
Obviously, this is a doozy. If the first letter of a line is "#", the rest of the line will be ignored. This is called a "comment." We can do this in assembly and other languages, as well. The next thing we'll note is that we can give something a name, then use the "=" to have everything to the right of it be represented by the thing on the left side. ASRC I set for sources in assembly, CSRC for sources made in C, and CPPSRC for sources in C++. CFLAGS is for that which gets invoked at the very end, apparently, where "-s" means "call the strip program." CPPFLAGS seems to be arguments passed when calling GCC and G++/GPP, so we're setting it to optimize by size. I then have correspoding ones for .o files, with this "X:Y=Z" seems to represent "for every X, find Y and replace it with Z", which forces me to have separate ones for each language. I then combine them all in OBJ ("${}" appears to mean "put the value of the thing here") for simplicity later on. I created an EOBJ then to represent the extra files that ld will need that GCC normally automatically hands off to LD, but I'm wanting to call LD manually to save time, since GCC on DJGPP seems to go through all the steps unnecessarily and it's incredibly slow on DOS. More on that later.
Next we have the actual recipies. These are the things called when you do something like "make run", where it does everything after "run" until either the end of the file or the "clean" (next recipie). .PHONY is a safety net for recipies that aren't named after files (maybe this is some sort of legacy feature to require this). When a recipie contains something after the colon, it tells make that said recipie and/or file must be made before anything else can take place. So, presumably, "make run" naturally calls "make all" since "all" is after the colon, which then calls "make main" because it needs that, which then it knows it needs the various object files, so it tries to derive them via some method unbeknownst to me. "make clean" won't work in DOS, but it's recommended to have it so you can get rid of files before throwing them in a ZIP or something. Normally, you'd want to do what's in "make main" via GCC so GCC can find the EOBJ files for us, but I needed to do it here for us in DOS to save us a ton of time in the compiling process when small changes are being made. You'll want to get rid of the "EOBJ = " line and change ld to gcc (removing the "${"EOBJ}" as well) when compiling for another system. If you need to use the trick I did for another system, I managed to get the list via passing "-Wl,-v" to gcc to get GCC to pass "-v" to LD which then tells us what all files it was attempting to link. You'll find it spits out alot of redundant files, so i cleaned it up a bit. There might still be some redundant files left over, but that won't hurt anything since it only ever links a file once, no matter how many times you ask it to link them.
Lastly, of course, the whole point of this was so we could just type "make" (if nothing is specified, "make all" is implied) and "make run" to make (teehee) things easier by not requiring us to type as much. On the flip side, this is the first time I've ever made a makefile like this, so I hope it lasts me a long time. When testing programs with CLI parameters, you'll likely want to put some sample command line params in the run side of things. If it's in the same folder as "main.S" type "make run" and see the program run. Now, the good news is, all we have to do to make this existing file work with other files is adding their name to the respective SRC line.
Get your own web kitty here!
©Copyright 2010-2023. All rights reserved.