Making a makefile for C program on linux - c

I have a C programming exercise, which I have written (and runs perfectly) in Visual Studio on Windows. I now have to make sure it runs OK on Linux as well, and need to create a makefile for it (it is part of the assignment). Here is my makefile:
all: genericdfs.a sudSolver
genericdfs.a: genericdfs.c genericdfs.h
gcc -Wvla -c genericdfs.c
ar rs genericdfs.a genericdfs.c
sudSolver.o: sudSolver.c sudTree.h genericdfs.h
gcc -Wvla -c sudSolver.c -lm
sudukutree.o: sudTree.c sudTree.h
gcc -c sudTree.c -lm
sudSolver: sudSolver.o sudTree.o genericdfs.a
gcc -Wvla sudSolver.o sudTree.o -L. -lgenericdfs -o sudukusolver -lm
clean:
rm -f sudSolver.o
rm -f sudTree.o
rm -f genericfs.o
OK so the main C file is sudSolver which has includes for sudTree.h and math.h (hence the -lm)
sudTree.c includes sudTree.h and genericdfs.h as well.
One of the requirements is to create a .a library which should be linked to the main C file at the linkage operation.
We were given next to nothing of an explanation as how to write these makefiles so all I wrote above was according to makefile tutorials I found online.
This makefile however doesn't work, there seems to be a problem with the linkage to the library as this is the error that is being returned:
cannot find cannot find -lgenericdfs
I tried shifting things around but nothing seems to work, another error which appeared when I put -L. genericfs.a in the linkage line:
genericdfs.a: error adding symbols: Archive has no index; run ranlib to add one
Could anyone please explain how I link to the .a library which was created? I suppose its not that complicated but for the life of me I cannot get it to work
Thank you to anyone who helps!
EDIT
I managed to make it work by changing the line
ar rs genericdfs.a genericdfs.c
into
ar rs libgenericdfs.a genericdfs.o
and updating final linkage line to libgenericdfs.a
But now there is a different problem. I included a couple rm -f commands to a clean: tag, but they don't delete the files written there when i run "make" from the terminal.
If I run "make clean" then everything gets removed. Do I need to add "clean" to the "all" tag at the top? I read that you should not do that

gcc is passed libraries by using
gcc -Lfull/path/to/library
Or if the library name starts with 'lib' and is on a library search path then you can use -l with lib and .a removed. For example with library called libtest.a .
gcc -ltest
There are a couple of special cases for well used libraries like maths -lm and zlib I think.

Related

How do I write a Makefile to link C code with Arm assembly code?

The following terminal commands will compile and link my .c and .s files in linux
rm *.o
gcc -c printS.c -o printS.o
as lab8.S -o lab8.o
gcc lab8.o printS.o -o lab8test
I have never written a make file and I figure something like this deserves one. Any help is appreciated.
The same way you would make any make file. I am sure there are tons of examples out there and web pages.
ideally_the_result : dependencies
<tab>the commands
<tab>the commands
<tab>the commands
so
printS.o : printS.c
gcc -c printS.c -o printS.o
And make a rule for each of the commands you are using. I recommend you put the last one first so that it is the default if you dont have a command line option on make
also
clean :
rm -f *.o
rm -f lab8test
to cover cleanup (make clean)
That is the super simple way that just works. From there you can dig into all kinds of (make program specific, gnu make vs others) special characters that mean things to make more complicated rules.

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, ....

Makefile, "nothing to be done for all" error

So I have a make file, stored in a directory called "temp" the following directory has a src folder, with 2 .c files "file1.c" and "file2.c". The temp directory also holds a include folder (which is empty), and a bin folder (which is empty until the make command is so posed to be run). I'm currently to trying get a single .c file to compile (get it working),but a single file doesn't even seem to work here.
This is how the directories look:
temp
cd into temp..
bin include Makefile src
Here is my makefile:
all:
gcc -Wall -pedantic -std=c99 src/file1.c -Iinclude -o bin/runMe -lncurses
And yes, there is a tab before the gcc. Any help on this frustrating issue, would be much appreciated. Also, if possible any input on compiling the second .c file, would also be very helpful!
Nothing to be done for TARGET means that a target has no commands which, in this case, almost certainly means that you do not have a tab on that gcc line.
That being said that's only the immediate problem. This makefile is also not following good practices and will unnecessarily recompile your program (as well as ceasing to work entirely should an all file be created).
DrC had, in a currently deleted answer, very good suggestions for how to improve your makefile to avoid both of those latter issues.
Specically, your makefile should look more like this:
.PHONY: all
all: bin/runMe
bin/runMe: src/file1.c
gcc -Wall -pedantic -std=c99 $^ -Iinclude -o $# -lncurses
Which marks the all target as a .PHONY so that an all file or directory getting created won't confuse make as well as setting up a prerequisite on the source file for your built binary so that make can tell when it does (and doesn't) need to rebuild the binary.

What is an efficient workflow with C? - Makefile + bash script

I'm working on one of my first projects that will span more than one C file. For my first couple practice programs, I just wrote my code in main.c and compiled using gcc main.c -o main. This worked for me as I was learning.
Now, I'm working on a much bigger project on my own. I want to continue doing compilation on my own (or at least setting it up manually) so I can understand the process. After reading a bit, I decided to make a Makefile.
Note: I'm also using GTK+, so I had to look up how to add that into the compile command.
This is what it looks like after a bit of research:
main:
gcc -Wall -g main.c -o main `pkg-config --cflags --libs gtk+-2.0`
At first, I was just running "make". Then I was having some problems getting the error "main is up to date" even though I had changed the file.
So I wrote a script:
#!/bin/bash
rm main
make
./main
So I make changes, and then I run this script.
Is this a good/normal system? I want to have scalable system, since my project will grow. I assume I can keep that script and just add dependencies to the makefile and change the main compile command in the makefile. Am I correct?
Thanks in advance.
EDIT:
Thanks for the feedback about how to fix my Makefile.
So is the typical compilation process 1) type make then 2) ./main regardless of how the project is setup or its size (assuming you've written a proper makefile)?
You need to tell make that main depends on main.c. That way every time you make changes to main.c and then run make, main is regenerated. To delete main you can have a phony target called clean as:
main:main.c
gcc -Wall -g main.c -o main `pkg-config --cflags --libs gtk+-2.0`
.PHONY: clean
clean:
rm -f main
Now to delete main you can do : make clean
If you get make: main is up to date. It means you've not modified main.c and hence there is not need for regenerating main. But if you have to force regenerating main even when the dependencies have not been updated you can also use the -B option of make as suggested by Sjoerd in other answer.
Use make -B or make --always-make to compile even though the target is up to date
Append filenames after the colon to check whether these are updated.
Example:
a: a.c
gcc -o a a.c
a would only be built if a.c is newer than a.
I find command-line make to be quite sufficient for my needs, but writing Makefiles by hand becomes quite a chore. As your project grows in complexity, you'll find managing the dependencies by hand to become more and more annoying. What I suggest you do is learn how to do at least one of the following:
Write a dependency-tracking Makefile by calling e.g., gcc -M.
Learn to use a Makefile generator such as automake or CMake. I personally prefer automake because it is more mature (and doesn't do stupid things like try to put semicolon-separated lists on a command line).

Compile multiple C files with make

(I am running Linux Ubuntu 9.10, so the extension for an executable is executablefile.out) I am just getting into modular programming (programming with multiple files) in C and I want to know how to compile multiple files in a single makefile. For example, what would be the makefile to compile these files: main.c, dbAdapter.c, dbAdapter.h? (By the way, If you haven't figured it out yet, the main function is in main.c) Also could someone post a link to the documentation of a makefile?
The links posted are all good. For you particular case you can try this. Essentially all Makefiles follow this pattern. Everything else is shortcuts and macros.
program: main.o dbAdapter.o
gcc -o program main.o dbAdapter.o
main.o: main.c dbAdapter.h
gcc -c main.c
dbAdapter.o dbAdapter.c dbAdapter.h
gcc -c dbAdapter.c
The key thing here is that the Makefile looks at rules sequentially and builds as certain items are needed.
It will first look at program and see that to build program, it needs something called main.o and dbAdapter.o.
It will then find main.o. However, to build main.o, it will need main.c and dbAdapter.h (I assume dbAdapter.h is included in main.c).
It will use those sources to build main.o by compiling it using gcc. The -c indicates the we only want to compile.
It does the same thing with dbAdapter.o. When it has those two object files, it is ready to link them. It uses the gcc compiler for this step as well. The -o indicates that we are creating a file called program.
GNU make should be what you're looking for.

Resources