Using Makefile to link multiple files - c

I'm kind of lost in the Makefile business and I'm trying to come to terms with it. I would love if someone could make it clear on an example I'm currently programming.
I have these files:
my-bit-vector.h -> a header file included in eratost.c, ppm.c
ppm.c -> a .c file which includes my-bit-vector.h and error.h
error.h -> a header file included in eratost.c, ppm.c
error.c -> a .c file which includes error.h and defines the functions in it
erato.c -> a .c file which includes my-bit-vector.h and error.h
I need to link these together into one executable file. How would I go about doing that via Makefile? I hope I didn't forget something. Could you please help?

The contents of a Makefile, when put simple, is one or more targets (the things you want built). Each target has dependencies (if any dependencies don't exist yet, they must be built, and if they do exist but they're newer than their target, the target must be rebuilt), and rules (the commands to build the target, presumably from the dependencies).
In your case, lets say your final output is a program called program. You've identified the sources to build it, but you don't build an executable directly from sources, you do it from object files. You could start your makefile like this:
program: ppm.o error.o erato.o
cc -o program ppm.o error.o erato.o
WARNING The spacing on rule lines (the cc command line shown above) requires a TAB, not just spaces!
That's enough to start but not enough to be right. You'll notice that there's no target:dependency/rules for the .o's yet, but it still works because Make has some built-in rules.
With this makefile, if you type "make" twice, the first time you'll see everything gets built and the second time it won't -- nothing changed so no rebuild is needed. Unfortunately if you edit your .h's now, the .c's still won't rebuild, so lets fix that:
program: ppm.o error.o erato.o
cc -o program ppm.o error.o erato.o
ppm.o: ppm.c my-bit-vector.h error.h
error.o: error.c error.h
erato.o: erato.c my-bit-vector.h error.h
Now you've got your dependencies set to cause make to rebuild sources that must be rebuilt when headers change. There's no rules on those source builds because the built-in rule here is (often) sufficient. You can override the built-in if necessary, of course.
Here, when you type "make", the tool will find the first target (program) and inspect its dependencies. It will then make sure each of its dependencies are up to date (based on their target:dependency / rule definitions), recursively as long as there are targets needing to be considered for being built. Finally it will apply the rules for this target to complete its build.
There's much more that can be done with makefiles, this is just a brief intro.

program: ppm.o error.o erato.o
gcc ppm.o error.o erato.o -o program
ppm.o: ppm.c
gcc -c ppm.c -o ppm.o
error.o: error.c
gcc -c error.c -o error.o
erato.o: erato.c
gcc -c erato.c -o erato.o
stuff before the ":" is the target. stuff after ":" are the required targets for this target.
So if you "make program" make is looking for a target named "all". The target all requires ppm.o which is also defined as target in the makefile. So it executes this target first. the target ppm.o requires ppm.c which has no target defined in the makefile, so it is probably a file. I hope this explains the basic functionality to you.
http://mrbook.org/tutorials/make/
is a really good tutorial for beginners, with some basic makefile examples.

Related

Including input statements and conditions in the make file

I am trying to create a makefile, for the first time. I went through some tutorials and I managed to create one, but I am having trouble with a couple of things. Below are the details.
Below are the files in the order of execution:
CSV_to_txt.c - no dependency on any other files.
I want to include CSV_files/Equilibrium_trajectories.csv, which is my input, in the make file. Further, I run the command tac Chemical_Equilibrium.txt in the terminal. Can I include this in the make file as well?
fluid_profile.c - depends on pdfutil.h and beta_util.h.
I have the same problem of reading the inputs, for ex:
Enter the number of points
1000 --> to be included in the make file.
This file creates a text file called fluid_points.txt. What I want to include in the makefile is if this file already exists don't execute the command gcc fluid_points.c -o fluid_points.o -lm.
Structure of the make file:
all:
gcc CSV_to_txt.c -o CSV_to_txt.o -lm
./CSV_to_txt.o
#Include the file path and name when asked for it
#ubuntu terminal command --> tac filename.txt > filename_changed.txt
gcc fluid_profile.c -o fluid_profile.o -lm
./fluid_profile.o
#Enter the number of points when prompted to do so
#If fluid_points.txt file is already existing don't execute the above command, instead execute the below one
gcc blah.c -o blah.o -lm
./blah.o
clean:
$(RM) *.o *~
Any sort of help or even a link to a tutorial would be helpful.
A suggested makefile:
run:
.PHONY: run
CSV_to_txt: CSV_to_txt.c
gcc CSV_to_txt.c -o CSV_to_txt -lm
fluid_profile: fluid_profile.c
gcc fluid_profile.c -o fluid_profile -lm
blah: blah.c
gcc blah -o blah.c -lm
run: CSV_to_txt fluid_profile blah
echo "CSV_files/Equilibrium_trajectories.csv" | ./CSV_to_txt.o
tac Chemical_Equilibrium.txt
echo "1000" | ./fluid_profile.o
./blah.o
clean:
$(RM) *.o *~
So, a break down -- first line, predeclare target run, such that it becomes the default target (if you do make, it will run the first target ). Declare this as a phony target (This means there's no actual file called run being produced. You can look up .PHONY for more details)
Then create some rules to generate the executables. Each executable has its own rule to generate it. Typically you would use automatic variables for these like $# and $<, but I wanted to keep it simple for now.
Then the rule for run. This is dependent on the executables (so executables will finish building before this rule runs).
Then, to pass the filename into the executable, you can simply echo the filename, and then pipe that into the executable.
You have a common newbie error... this is to think that a source file depends on other source files (a .c file depends on some .h files) This is an error and probably the cause you are not getting your result.
The objective of a Makefile is to describe file dependencies in order to do the minimum set of commands to build the final target you specify. For this you need to think that a target is something you are goint to create.
Is a source .c file something you create during the build proces? Not, so it cannot be a target of a rule. The target, indeed is the result of the compilation. The source file doesn't depend on a header file... it just includes it to make the compilation of the .o target (this is, actually the target).
Let's say you have a program hello.c that includes modA.h and modB.h. (and even modB.h includes modB2.h) If you modify any of them, you need to recompile hello.c, so your rule will be:
# (1)
hello.o: hello.c modA.h modB.h modB2.h
cc -c hello.c # (2) see below.
(1) a rule line starts at column 1 and has a left hand side (the target file) and a list of sources (dependencies). Each time make sees that the target doesn't exist or has a last change date earlier than the change dates of any of the dependencies, the command lines below are executed, one after the other.
(2) a command rule starts with a <tab> char in the first column of the line. It represents a command (or a list of commands, each in it's command line) that are required to generate the target file from the sources.
a line starting with # is a comment line (also valid to start in the middle of a rule or a command line)
There is anothe type of line (a macro definition) but you need to learn first how to create dependencies and get used to them, before starting learning how to create macros. Read the make(1) doc first.
you see that we only compile hello.c, but we have to do it every time we change any of the other files above. There are two modules, modA.o and modB.o, each of them with their .c file and the includes needed in hello.c. So:
modA.o: modA.c modA.h
cc -c modA.c
modB.o: modB.c modB.h modB2.h
cc -c modB.c
so when we change any of modA.c or modA.h then modA.o will be created. And as modB.h we said above that included modB2.h, then if we modify it, it should be compiled.
Now the dependency of the program to be linked: As the program is compiled, it has just three modules: hello.o, modA.o and modB.o. To create hello all these three modules must be given to the linker.... so the Makefile needs also:
hello: hello.o modA.o modB.o
cc -o hello hello.o modA.o modB.o
and so, the complete Makefile is:
# this rule is put first to become the default target.
# the default target is the final program.
hello: hello.o modA.o modB.o
cc -o hello hello.o modA.o modB.o
# this rule is for the hello.o target only.
hello.o: hello.c modA.h modB.h modB2.h
cc -c hello.c
# this rule is for modA.o
modA.o: modA.c modA.h
cc -c modA.c
# and this one for modB.o
modB.o: modB.c modB.h modB2.h
cc -c modB.c
and with this Makefile you'll enjoy, because you can touch any file, but the compiler will compile only the correct dependencies to generate the final executable program.
Make has a lot of more functionality, but that requires you to know at least the most basic of it. Once after you have succeeded on the creation of the correct dependencies, you can start to study the other facilities of make, that are only there to abbreviate/avoid rewritting the same thing several times. But read at least the make manual page.

Error in makefile ("no input files")

This is my absolute first time ever making a makefile, and I'm really trying to understand the process.
I'm trying to create a very simple makefile for a C++ project whose structure is as follows:
root folder
makefile
readme
src folder
...source files all here...
include folder
...header files for external libraries here...
lib folder
...external lib files all here...
bin folder
...output directory for built executable...
obj folder
...object files all here...
I followed the tutorial here.
Here's my makefile:
IDIR=include .
CC=g++
CFLAGS=-I$(IDIR)
ODIR=bin/obj
LDIR=lib
LIBS=none
SRC=src
_DEPS=hello.h
DEPS=$(patsubst %,$(IDIR)/,%(_DEPS))
_OBJ=file1.o file2.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: $(SRC)/%.cpp $(DEPS)
$(CC) -c -o $# $< $(CFLAGS) # $(LIBS)
test_proj: $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
When I run make on this, I get the following error:
g++ -o .o
g++: fatal error: no input files
compilation terminated.
<builtin>: recipe for target '.o' failed
mingw32-make.exe: *** [.o] Error 1
I'm using GNU Make 3.82.90 built for i686-pc-mingw32, if that matters at all.
Can anyone point out whatever ridiculous error I'm making?
IDIR=include .
is the first problem. Replace it by:
IDIR=include
With your code CFLAGS is expanded as:
-Iinclude .
It does not make sense, I'm afraid. The second problem is:
DEPS=$(patsubst %,$(IDIR)/,%(_DEPS))
which should probably be:
DEPS=$(patsubst %,$(IDIR)/%,$(_DEPS))
and would expand as:
DEPS=include/hello.h
if you fix the first problem, else as:
DEPS=include ./hello.h
which does not make sense neither. The cumulated effect of these two errors are strange recipes (I didn't try to expand them by hand) that probably trigger a make implicit rule with wrong parameters.
IDIR=include .
CC=g++
CFLAGS=-I$(IDIR)
This is wrong. First, for C++ code, use CXX not CC and CXXFLAGS not CFLAGS. Run make -p to understand the builtin rules of your make.
Then -I$(IDIR) does not "distribute" the -I, and IDIR is never used elsewhere. So I suggest to start your Makefile with:
CXX=g++
MY_CXX_LANG_FLAGS= -std=c++11
MY_CXX_WARN_FLAGS= -Wall -Wextra
MY_CXX_INCL_FLAGS= -I. -Iinclude
MY_CXX_MACRO_FLAGS= -DMYFOO=32
### replace with -O2 for a release build below
MY_CXX_OPTIM_FLAGS= -g
CXXFLAGS= $(MY_CXX_LANG_FLAGS) $(MY_CXX_WARN_FLAGS) \
$(MY_CXX_INCL_FLAGS) $(MY_CXX_MACRO_FLAGS)
I won't improve your Makefile, but I do suggest to upgrade to GNU make version 4 if possible (and compiling make 4.1 from its source code is worthwhile in 2015) for that purpose. If possible enable GUILE scripting in it.
If you are forced to use make 3.82 debug your Makefile using remake (with -x); if you can afford a make version 4 use its --trace option
BTW, you might consider using automatic dependencies, that is generating dependencies by passing -M or -MG (etc) flags of g++, see that.
At last, a simple project for a small program (less than a hundred thousands of source lines) might just put all (a few dozens of) its files in the current directory (then the Makefile could be simpler); your proposed directory structure might be arcane for a simple project (but could worth the pain if you have millions of C++ source lines of code). I've given several simple examples of Makefile, e.g. this & that. And GNU make source code itself has a less complex file tree that what you want.
BTW, I strongly disagree with the opinions of that answer (which I did upvote, since it is helpful). I don't feel that GNU make is senile, but I regret that, instead of using recent features available on recent versions (4.x) of make, many people prefer to use complex and arcane Makefile generators (like cmake) instead of coding a clever Makefile (for make version 4 specifically).
At last, you could use other builders, e.g. omake, icmake, ....

generating a makefile for the dumb

I got 10 C files.
10 h files all in one folder.
I need those files to create 1 executable in the same folder using unix makefile.
EDIT :
the soultion
create a file named "makefile"
write the following make sure you have a single TAB before the word "gcc" this will create a.out executable
all:
gcc *.c
if you need flags just add them for example to make the filename BOB:
all:
gcc *.c -o BOB
I don't think you want what you say you want, but how about:
all:
gcc *.c
"missing separator" is commonly caused by a missing tab in front of a command line. The lines with $(CXX) need to be indented by a tab - not 8 spaces, not any number of spaces, but a tab.
Additionally, I don't think that empty lines between rule and commands are allowed.
Apart from obviously writing the Makefile yourself, you can also use CMake which is a convenient build system generator.
A simple example of a CMakeLists.txt file:
cmake_minimum_required(VERSION 2.6)
project(yourproject C)
add_executable(yourexecutable file1.c file1.h file2.c file2.h ...)
You can then do in a terminal:
$ cmake .
$ make
and your executable will be built.
Be careful however that the generated makefile uses cmake and is therefore not distributable per se.

Getting undefined references when linking against a static library

I made a static library with GCC. Building of the library was OK.
When I use it the linker throws undefined reference errors on some functions. But nm says the functions are defined and exported in the static library (marked with T). I know about the linking order that I need to put the libraries after that module that needs them so this can not be a problem.
The static library was built from 3 C files. A.c B.c and D.c The D module depend on A and B (includes their headers).
No problem when I use functions from A and B but when I try to use any function from D I get undefined reference errors on them.
If I move these functions in A or B it works. But not if they are in the D module.
I'm completely run out of ideas what's going on or what is I'm overlooked.
I'm using Code::Blocks and working with plain C files.
An old trick that many times works: List each static library twice in the linking phase.
i.e., in your makefile (or whatever you're using), put:
gcc -o <outfile> <liba> <libb> <libc> <liba> <libb> <libc>
Anyway, I hope you get the idea.
I found out that I added A .cpp file to my project and I just renamed it to .c. I chose C language instead of C++ when I created the project. I did't think this could cause problems
I thought the file extension decides when the IDE chooses between gcc and g++. But not. In Code::Blocks if you add a file with a .cpp extension it will use g++. If you add a file with a .c extension it will use gcc. But if you rename the file it will use the same compiler. You have to change it explicitly in the project options.
That D module was built using g++ instead of gcc.
I realized this when I set the IDE to show me the entire command line when building not just "Compiling foo.c".
In the master make file I wrote to simplify my application/library builds, the solution I used was to run the link step twice. Using the -u linker option to specify undefined symbols on the second link.
In my make file I have a target like this:
undefined.txt:
#$(generate-undefined-syms)
which calls this macro... the first attempt at linking...
define generate-undefined-syms
$(PRINTF) "$(this_makefile): Generating undefined symbols ... \n"
$(CC) -o rubbish $(LDFLAGS) $(objects) $(LDLIBS) 2>&1 | $(GREP) 'undefined reference' > tmp.txt; \
$(SED) 's/^.*`/-Wl,-u/g' < tmp.txt > undefined.txt; \
rm -f tmp.txt rubbish
endef
As my sed/regexp skills aren't good (and I wrote this stuff in a rush) I end up with undefined.txt containing:
-uSomeSym'
-uSomeOtherSym'
i.e. with a trailing '
I then use this make syntax to strip the 's, and remove duplicates
undefined_references = $(filter-out follow, $(sort $(subst ',,$(shell cat undefined.txt))))
The 'follow' filter is because if an undefined symbol is referenced many times, a message "more references to XXX follow" appears in the output, which leads to a spurious 'follow' in the undefined.txt file e.g.
-Wl, uXXXX' follow
Finally I link the second time (note the dependency on undefined.txt)
$(application): $(library_dependencies) $(objects) undefined.txt
$(CC) -o $# $(LDFLAGS) $(undefined_references) $(objects) $(LDLIBS)
I'd totally recommed the following book by the way, as I was able to write from scratch a simple build system in a couple of days.
Managing Projects with GNU Make, Third Edition
By: Robert Mecklenburg
Perhaps you should use ranlib or the approriate ar option to provide an index to your .a file.

Compiling Small Gcc Project on Windows Using MinGW

so I've been programming in C++ for almost 2 years now, and the whole while I've had the pleasure of using an IDE (VS) with lovely project settings and automatic linking and the like. I've always stayed away from any external libraries which required me to compile via makefiles, or at least the ones which were meant for linux environments/other compilers.
Anyways I now want to use a super handy utility (Bob Jenkins Perfect Minimal Hash) but it requires me to compile via makefiles, not only that but using the g++ compiler.
I went ahead and got the mingW32-make utility and am now trying to get it to work. Where I'm at now:
Succesfully installed minGW
Succesfully called the make utility
Failed to succesfully make the project.
The error I get is:
C:\gen_progs\ph>mingw32-make
mingw32-make: *** No rule to make
target lookupa.c', needed by lookupa.o'. Stop.
And the makefile itself:
CFLAGS = -O
.cc.o:
gcc $(CFLAGS) -c $<
O = lookupa.o recycle.o perfhex.o perfect.o
const64 : $(O)
gcc -o perfect $(O) -lm
# DEPENDENCIES
lookupa.o : lookupa.c standard.h lookupa.h
recycle.o : recycle.c standard.h recycle.h
perfhex.o : perfhex.c standard.h lookupa.h recycle.h perfect.h
perfect.o : perfect.c standard.h lookupa.h recycle.h perfect.h
Now the error seems reasonable, at least from my minimal understanding of makefiles, I have all the referenced .c, .h files, however I have none of the .o files and there doesn't appear to be any instructions on how to make these. So my question/s are:
am I calling the make utility wrong? Or do I need to compile the object files first? Or... do I need to add something to the make file?
Again I have all the referenced .c and .h files.
Edit: Sorry about that I was actually missing that specific file it seems to have disapeared somewhere along the line. However, adding it back in this is the error I now get:
c:\gen_progs\ph>mingw32-make
cc -O -c -o lookupa.o lookupa.c
process_begin: CreateProcess(NULL, cc -O -c -o lookupa.o lookupa.c, ...) failed.
make (e=2): The system cannot find the file specified.
mingw32-make: *** [lookupa.o] Error 2
Regarding your error "process_begin: CreateProcess(NULL, cc -O -c -o lookupa.o lookupa.c, ...) failed."
This is because the make utility wants to use the "cc" compiler to compile your program, but that compiler is not part of the Mingw-package.
Solution: Change the ".cc.o:" to ".c.o:". This changes the implicit rule which tells Make what compiler to use (gcc on the next line) when compiling .c files (the original line tells it how to compile .cc files).
Saying either make -DCC=gcc at the command line or adding the line CC=gcc to the top of the Makefile would cure the issue as well. Make's built in rules for handling C source code all name the C compiler with the variable CC, which defaults to "cc" for reasons of backward compatibility even in Gnu Make.
It looks like the original Makefile author tried to work around that problem by supplying a custom rule for compiling .cc files, but since there are no .cc files in the project that rule was not actually used.
Specifying the correct value for CC is superior to fixing the explicit rule to name .c files IMHO because Makefiles are generally easier to use and maintain and are the most portable when the least possible information is specified.
I don't think not having .o files is the problem. Make will make them from the source files (the files to the right of the colon).
Your immediate problem seems to be that make can't file the file "lookupa.c". From the rules you posted, it looks to me like that file should be sitting in the same directory as the makefile, but it isn't. You need to figure out where that file is, and how to get it there.
(For some reason I have a mental image of Wile E. Coyote sitting at his computer, seeing that file name, looking up, and getting plastered with an anvil).

Resources