Generate output files in separate directory in c using make file - c

How can i build a c project using makefile that generate intermediate and output files in separate directory other than source?
Current form of my makefile is
CC = g++
LDLIBS = -lm
all: test_makefile
test_makefile: file1.o file2.o file3.o file4.o test_makefile.o
clean:
rm test_makefile *.o
I want to generate these intermediate files in /build directory.
Can anyone help me to modify this make file?

You might want to consider using Automake (https://www.gnu.org/software/automake/) for projects of significant size with separate source and build directories.
Without automake, and considering that by default compilers generate output files in CWD, you can simply create your makefile in the build directory. Here's an example that uses ../ as source directory:
all: foo
foo: ../x.cc
$(CXX) $< -o $#

Related

Binary is not rebuilding when source file changes

I have a directory structure like the following:
Makefile
bin
main.c
Makefile
lib
lib1.c
lib2.c
Makefile
tst
test1.cc
Makefile
In my Makfile I have code the looks like this:
ALL_OBJECTS = main.o lib1.o lib2.o
BINS = binary
binary,SRCS = main.o lib1.o lib2.o
OBJS = $($(*),SRCS)
all: $(ALL_OBJECTS) $(BINS)
%.o : %.c
${CC} -c $^ -o $#
binary:
${CC} -o $# $(OBJS)
My question is when I change and of the source files like main.c, lib1.c or lib2.c the *.o file is re-compiled during make but the binary is not recompiled. How can I ensure that the binary is recompiled when one of its dependencies change?
Some parts of your Makefile don't make much sense to me, and the directory structure you show doesn't really seem to match up well with the Makefile you show. For example, with a directory named lib that contains a Makefile of its own, I'd expect to see that Makefile create a library that depends on lib1.o and lib2.o. Then binary would depend on that library.
But right now, it looks like you're just building binary from a single Makefile, and ignoring the Makefile in the lib directory. That can work too, but it's going to be different from the previous scenario.
For the moment, let's start with a bit "flatter" directory structure, with main.c, lib1.c and lib2.c all contained in a single directory (and the Makefile in that same directory). For this case, we can build the binary with a really simple Makefile:
binary: lib1.o lib2.o main.o
$(CC) -o binary lib1.o lib2.o main.o
We just make that the binary depends on the object files, and how to create the binary from those object files. Any reasonable modern make utility already has built-in rules for how to compile a .c file to produce a .o file, so we don't have to do any more than that unless we want something fairly unusual in how we build those object files.
That does repeat the names of the object files in two places though. We'd usually prefer to avoid that. We can separate out defining the names of the object files from the rule to make the binary from them, to get something more like this:
OBJS = lib1.o lib2.o main.o
binary: $(OBJS)
$(CC) -o binary $(OBJS)
Now we only have the names of the object files in one place, so if (for one obvious example) we add another object file, we only need to add its name in one place, rather than two.
Based on your last comment to #JerryCoffin's answer, you could do something like this:
binary1 : lib1.o lib2.o main1.o
binary2 : lib2.o main2.o
binary3 : lib1.o main3.o
binary1 binary2 binary3:
$(CC) -o $# $^
The first three lines have no recipe, and thus simply are adding prerequisites to the associated binaries. Then you define a recipe for the binary targets using the automatic variable $^, which will expand to that target's dependencies.

How can I compile a header file and a C file together?

I created a file.h and a file.c how can I compile them on Ubuntu?
You only need to compile your .c file(s), not your .h file(s).
To compile file.c on Ubuntu, you can use GCC:
gcc file.c -o my_program
...or Clang:
clang file.c -o my_program
It is possible to precompile your header files, but you only need precompiled headers in particular cases. More information here.
If file.h is not in the same folder as file.c, you can use GCC or Clang's -I option.
Example if file.h is in the include/ folder:
gcc -I include/ file.c -o my_program
In file.c you still have this instruction, with only the filename:
#include "file.h"
You can also use a more generic approach by the usage of a makefile.
Here is a short example of such a file:
# Declaration of variables
CC = gcc
CC_FLAGS = -w -Werror -Wall
# File names
# "prgoram" will be the name of the output produced from the make process
EXEC = program
#Incorporates all the files with .c extension
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
# Main target
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
# To obtain object files
%.o: %.c
$(CC) -c $(CC_FLAGS) $< -o $#
# To remove generated files
clean:
rm -f $(EXEC) $(OBJECTS)
To use this utility just make sure that the file itself is within the directory containing your source files and its name is either "makefile" or "Makefile".
To compile the code simply run the following command from your working directory:
make program
This command will automatically link all the source files within your working directory into one executable file with the name of "program". To run the program itself just use the command:
./program
To clean your project and the created executable you can run the command:
make clean
The makefile is very powerful when dealing with larger projects that contain a larger number of source files. Here you can check for more guidance on how to use makefiles. This is also a very detailed tutorial on the topic.
Use following command to compile your program(For GCC Compiler):
gcc file.c -o file
No need to compile file.h file.

How to link objects from different directory (running ld)

I'm writing simple makefile project.
I'm trying to build the program in two steps:
compile source files and save object files in an different directory
link the objects into an executable
consider something simple like:
all:
gcc -o ~/some_dir/main.o -c main.c
ld -o my_program main.o
the problem is the invoke directory isn't "~/some_dir" so ld doesn't find the object file... how can I include "some_dir" in ld search path?
In the more global perspective, I have object files in various directories and I'd like to link them all together using a single linker command file.
Thanks.
You're makings things far more complicated than they need to be and should let make do more of the work for you. Below is your simple example re-written
SRCS=main.c
BUILDDIR=~/somedir
OBJS=$(SRCS:%.c=$(BUILDDIR)/%.o)
CFLAGS=-g
all: my_program
my_program: $(OBJS)
$(CC) $(CFLAGS) -o $# $^
$(BUILDDIR)/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $^
It defines a number of variables at the top, such as SRCS which would contain a list of your source files, the directory where you're storing the object files and generates a list of what object files you'll be building. Then it uses $(OBJS) to define that they are dependencies of my_program. The $# in the make rule is a variable meaning "the thing that we are building" and $^ is the list of dependencies. You can add other dependencies to my_program and don't need to change the command being ran.
Then there is a rule that defines how object files in $(BUILDDIR) are built from source files in the current directory.

Why is my makefile recompiling even if I just compiled the source?

I have a simple makefile that compiles a p.c file to an executable using gcc on Linux.
The p.c file depends on a a.h file.
My makefile looks like this:
//makefile
CC = gcc
build: p.c a.h
$(CC) -o out p.c
clean:
rm -f *.exe
rebuild: clean build
Your makefile doesn't produce the files it promises to produce, namely build, clean and rebuild. Since these targets are not files they should be marked as phony targets:
.PHONY: build clean rebuild
build target should be:
build : out
out : p.c a.h
$(CC) -o $# p.c
This part
build: p.c a.h
$(CC) -o out p.c
says "I'm compiling with $(CC) -o out p.c and the result will be a file named 'build'". Since you lied to make (this creates the out file instead), it will try building 'build' again.
There's a lesson for Makefile writers here: always use the $# variable (denoting the target) to avoid this error:
out: p.c a.h
$(CC) -o $# p.c
For more advice, see Paul's Rules for Makefiles.
Learner, here is an example of using a variable to store the name of the executable. This way you only need to specify it in one place at the start of your Makefile:
EXECUTABLE = out
.PHONY: build clean rebuild
build: $(EXECUTABLE)
$(EXECUTABLE): p.c a.h
$(CC) -o $# p.c
clean:
rm -f $(EXECUTABLE)
rebuild: clean build
Normally you would also have your .c and .h files listed in variables too so that you can add/remove files from your build easily without having to search through your Makefile for all of the places that they are used.
Makefiles have the general syntax:
target : dependencies
commands to make target from dependencies
So your Makefile expects to make a file called build using the build : p.c a.h target.
Since the commands don't actually make this file each time you call make it's having to redo the command.
(PS: Linux binaries don't have a .exe extension)
If you want to avoid always recompiling the source, then your target should depend on the object file, not the source file:
target.exe : p.o
$(CC) -o $# $?;
p.o: p.c a.h
$(CC) -c $# $?;
A typical makefile doesn't usually have an explicit rule per object file, nor does it usually list explicit dependencies between implementation and header files; you usually see an implicit rule like
%.o : %.c
$(CC) -c $(CFLAGS) $?;
(where $? indicates the list of prerequisites for that target) or, if your project is dead simple (one source file), you don't even need that; you can usually get away with
all: target
target: target.o
assuming you have a file named target.c, the above will build target using the default compiler and CFLAGS options.
Likewise, a typical makefile (at least in my experience) doesn't explicitly list header dependencies; rather, it relies on a compiler option to generate those dependency lists automagically (for gcc, that option is -M). See here for an example.
I have understood that it is necessary for the 'target' and 'output file' names to match fully for the make to be able to recognize if recompilation is not required. So in case of Windows environment (as make I have tried mingw32-make.exe) it should be like this:
build.exe: p.c a.h
gcc -o build.exe p.c
or
build.exe: p.c a.h
gcc -o build p.c # .exe is added automatically to generated file
This code will lead to recompilation always when make is called:
build: p.c a.h
gcc -o build p.c # target is "build" and it is not the same as "build.exe" which is the output of compilation

What is wrong with this Makefile? (header files not found)

I am modifying an old makefile in order to build a C extension for postgreSQL. The Makefile currently looks like this:
PGLIB = /usr/lib/postgresql/8.4/lib
PQINC = /usr/include/postgresql/8.4/server
CC=gcc
override CFLAGS+= $(CFLAGS_SL) -DPG_AGGREGATE
SHLIB = pg_myextlib
SRC = foo.c \
foobar.c
OBJS = foo.o \
foobar.o
all: $(OBJS)
$(CC) -shared -o $(SHLIB)$(DLSUFFIX) $(OBJS) -I$(PQINC)
cp *.so $(PGLIB)
clean:
rm -f $(SHLIB) $(OBJS)
The error I get when I run make is:
common.h:58:22: error: postgres.h: No such file or directory
Which suggests that the include path is not being added (the file exists in $PQINC).
Its a long time since I wrote the Makefile - and I haven't written many since. As an aside, I am pretty sure that 'shared' is not the gcc flag to build shared libs on Ubuntu (my current dev box) - I think the flag should be 'fPIC' - can someone confirm this?
I am runing gcc v4.4.3 on Ubuntu 10.0.4 and compiling for use with PG 8.4
Try moving the -I$(PQINC) from target all to the end of line that starts with override CFLAGS.
Placing -Isomething on the compiler line which turns object files, like those in $(OBJS), into executable will have no effect whatsoever.
You need to do it when you compile the source files.
Since your makefile doesn't explicitly show the rule for processing source files, it may well be using a default one, which is incredibly unlikely to know about PQINC.
You seem to be using the default rules to build foo.o from foo.c, which doesn't have your -I. Try adding the following rule to your Makefile:
.c.o:
$(CC) $(CFLAGS) -c $< -o $# -I$(PQINC)

Resources