How can I write Makefile (with sub Makfile ) more concise - c

When I do practice , I have a practice path.
Under this path , I have an Include path named myInclude (I have some useful function is this folder and I always use it.)
And a code path named symbol_try.I always make add new folder (with a c file and main function in it) in symbol_try and compile it.
Each time I have to compile it by gcc in terminal .Its a boring work , so I write a Makefile.
Here is an example:
the main Makefile in practice path:
FOBJS=
include myInclude/Rule.mk
include symbol_try/codeList_13.1/Rule.mk
symbol:$(FOBJS) <==What exactly I what . A executable file.
gcc -o symbol $(FOBJS) -pthread -lpthread
subsystem:
cd myInclude/ && $(MAKE)
cd symbol_try/codeList_13.1/ &&$(MAKE)
clean:
rm -rf symbol
In the myInclude/Rule.mk
FOBJS+=myInclude/otherFunction.o myInclude/error.o \
myInclude/unit.o myInclude/unitTest.o\
In the symbol_try/codeList_13.1/Rule.mk
FOBJS+=symbol_try/codeList_13.1/codeList_13.1.o
In myInclude/Makefile:
OBJS=otherFunction.o error.o unit.o unitTest.o
ALL:$(OBJS)
.PHONY:ALL
$(OBJS):%.o:%.c
gcc -c $< -o $#
clean :
otherFunction.o error.o unit.o
In symbol_try/codeList_13.1/Makefile:
codeList_13.1.o:codeList_13.1.c
gcc -c codeList_13.1.c
Well.That can work. But as you see , I have to write a Rule.mk(to initialize the FOBJS) and a Makefile for each folder.
I am new for make , I want find a way more concise , witch I only need write one Makefile for each folder and a main Makefile.No Rule.mk any more.
PS: I always change the code in myInclude ,so I don't want to build it a library.
Thanks for any help.

Here's one way you can do it with just one Makefile:
CC = gcc
CPPFLAGS += -I myInclude/ (1)
CFLAGS += -std=c99 -Wall (2)
VPATH = myInclude/ \ (3)
symbol_try/codeList_13.1/
symbol: otherFunction.o error.o unit.o unitTest.o codeList_13.1.o (4)
$(CC) -o $# $^ (5)
.PHONY : clean
clean:
rm -f symbol *.o
Note that make knows how to build C files and has some standard macros: CC, CPPFLGAS, CFLAGS
Add the include paths of your headers. You presumably have some headers for the individual object files in the myInclude directory.
Put the compiler flags here.
Add the paths to the source files you want to build.
List the object files that the executable depends upon
As there is no file called symbol.c you need to tell make how to create symbol.o with a rule. $# means the target ('symbol', here), and $^ means all of the prerequisites (the object files listed).
Here's a list of all of the files in my test directories for this:
$ find . -type f
.
./Makefile
./myInclude/error.c
./myInclude/header.h
./myInclude/otherFunction.c
./myInclude/unit.c
./myInclude/unitTest.c
./symbol_try/codeList_13.1/codeList_13.1.c
And the build output:
$ make
gcc -std=c99 -Wall -I myInclude/ -c -o otherFunction.o myInclude/otherFunction.c
gcc -std=c99 -Wall -I myInclude/ -c -o error.o myInclude/error.c
gcc -std=c99 -Wall -I myInclude/ -c -o unit.o myInclude/unit.c
gcc -std=c99 -Wall -I myInclude/ -c -o unitTest.o myInclude/unitTest.c
gcc -std=c99 -Wall -I myInclude/ -c -o codeList_13.1.o symbol_try/codeList_13.1/codeList_13.1.c
gcc -o symbol otherFunction.o error.o unit.o unitTest.o codeList_13.1.o

Why don't you create a library from the objects in myInclude and do the linking in the Makefile in your code path (symbol_try/codeList_13.1). The latter is better anyway because the needed libraries (-pthread -lpthread in your case) might change as well for some other code.
The main Makefile now would have got nothing to do but call make in all needed subdirectories.

In each folder have a makefile with
SOURCES=sample.c sampletest.c
OBJECTS=$(SOURCES:%.c=$(OBJDIR)/%.o)
all: $(OBJECTS)
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -o $# $<
In the root directory of a project, create a makefile with a rule to compile every sub-folder like the below.
Dirs= path-to-rootdir
objs:
set -e ; \
for i in $(Dirs) ; do \
$(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS_MODULE)" LDFLAGS="$(LDFLAGS)" OBJDIR="$(OBJDIR)" -C $$i; \
done
And then you could use it build the executable by adding a rule
EXE: objs
$(CC) -L./Path1 $(LIB_PATH) -llib1 -o $(EXE_NAME) $(wildcard $(OBJDIR)/*.o)
Hope this helps!!!

Related

MAKEFILE using Library : Linker command failed

Hello I can't make my Makefile working with
$(CC) $(CFLAGS) $(INC) $(OBJS) $(MLX_LNK) -o $(NAME).
got a
clang -O3 -Wall -Wextra -Werror -I -I cub3d.h src/cub3d.o src/checks/argvcheck.o src/checks/parse_map.o src/libft/basics.o src/libft/basics_bis.o src/libft/get_next_line.o src/utils/errors.o -L minilibx_opengl -lmlx -framework OpenGL -framework AppKit -o cub3D
clang: error: cannot specify -o when generating multiple output files
make: *** [cub3D] Error 1
The command on terminal I do is "make test1"
I also tried with $(CC) $(CFLAGS) -I $(HEADER) $(OBJS) $(MLX_LNK) -o $(NAME).
but got
Compiling...
clang -O3 -Wall -Wextra -Werror -I cub3d.h src/cub3d.o src/checks/argvcheck.o src/checks/parse_map.o src/libft/basics.o src/libft/basics_bis.o src/libft/get_next_line.o src/utils/errors.o -L minilibx_opengl -lmlx -framework OpenGL -framework AppKit -o cub3D
Undefined symbols for architecture x86_64:
"_init_cube", referenced from:
_init_game in cub3d.o
"_write_errors", referenced from:
_verify_line in argvcheck.o
_ft_parse_cub in argvcheck.o
_my_get_next_line in get_next_line.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Many thanks for your help
Makefile here :
NAME = cub3D
HEADER = cub3d.h
CC = clang
CFLAGS = -O3 -Wall -Wextra -Werror
INC = -I $(MLX-DIR) -I $(HEADER)
MLX_DIR = minilibx_opengl
MLX_LNK = -L $(MLX_DIR) -lmlx -framework OpenGL -framework AppKit
SRCS = src/main.c \
src/checks/argvcheck.c \
src/libft/basics.c \
src/libft/get_next_line.c \
src/utils/errors.c \
OBJS = $(SRCS.c=.o)
all: $(NAME)
mlx: $(MLX-DIR)
#echo "\033[34m-= Making libX.a... =-"
#make -C $(MLX_DIR)
$(NAME): ${OBJS} mlx
$(CC) $(CFLAGS) $(INC) $(OBJS) $(MLX_LNK) -o $(NAME)
test1: $(NAME)
$(NAME) ; ./a.out maps/test1.cub
clean:
#echo "\033[0;31mCleaning..."
rm -f $(OBJS)
# + $(B_OBJ)
# + rm -f bitmap.bmp
#echo "\033[0m"
fclean: clean
#echo "\033[34m-= Cleaning mlx... =-"
#make clean -C $(MLX_DIR)
#echo "\033[0;31mRemoving executable..."
rm -f $(NAME)
#echo "\033[0m"
re: fclean all
.PHONY: all clean fclean re
````
Well, first of all this is wrong:
OBJS = $(SRCS.c=.o)
You're missing a : here, it should be $(SRCS:.c=.o) As a result, OBJS will be empty.
Next, this is not causing you problems at the moment but is not right: you should always use $(MAKE) never a raw command like make when invoking a sub-make.
Finally, the way you've written your question by embedding results into the middle of the makefile makes it very hard to read. Please put the makefile first, then separate sections for different attempts at recipes. And you need to include the command line that make printed out (cut and paste the exact line please!) for us to see what the command being run it (with all variables expanded). Typically it becomes VERY obvious what the problem is if you look at that.
For example in this case you'd see that there are actually no object files in the link line, so it should be clear that the $(OBJS) variable is not being set properly.
EDIT
OK, thanks for showing the command line. Now, you should look at it carefully and you will see your problem :). Look at this here:
clang -O3 -Wall -Wextra -Werror -I -I cub3d.h src/cub3d.o ...
Does that look right to you? Look specifically at -I -I cub3d.h... does that seem right?
What happens is that the compiler expects a pathname to come after the -I and there isn't one, so it treats the second -I as the pathname. Then the file cub3d.h is treated as a source file, and you can't link a source file with object files.
So why does this look like this? Look at your makefile:
INC = -I $(MLX-DIR) -I $(HEADER)
so the missing thing is where $(MLX-DIR) goes. What is that variable? Well you have this:
MLX_DIR = minilibx_opengl
but this is not the same thing because it uses an underscore whereas the reference uses a dash. So, make them the same.
Then you'll see that it's not valid to put a file as an argument to -I. That takes a directory to search for header files. If you want to include the header you have to add #include "cub3d.h" in your source code, not add it to the compile line.

When I use "gcc" in makefile, after making it, I got a "cc" output

For example:
There are 3 source files {main.c test1.c test2.c} in the directory
and a directory file named test3,
and there is a source file named test.c in the directory of test3.
Now I want to create a makefile to compile and link these four source files.
And this is my Makefile:
# Cancel statement "CC=gcc"
src:=$(wildcard *.c) test3.c
obj:=$(patsubst %.c,%.o,$(src))
main:$(obj)
gcc -o main $(obj)
.PHONY:clean
clean:
rm *.o *~
When I called make to compile them, I got a output like this:
cc -c -o main.o main.c
cc -c -o test1.o test1.c
cc -c -o test2.o test2.c
cc -c -o test3.o test3/test3.c
gcc -o main main.o test1.o test2.o test3.o
I know 'cc' is linked to 'gcc' in Linux.
What I don't understand is why did Make call cc to compile these four source files, but call gcc to link the object files?
You changed one rule: the one that links the program main from the object files. And when make did that link, you can see it used gcc.
You didn't do anything to change the built-in rules that make is using to compile the object files, so they use the default (the value of the variable CC) which is cc.
You wrote only the rule to link the object files, and allowed Make to use its default rule to decide how to build the object files from the source files.
GNU Make will expose its rules if you ask it with --print-data-base. In this case, it tells us
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
and
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
and finally
CC = cc
This explains why Make uses cc to compile your C sources. To change that, simply set CC = gcc. Here's a complete Makefile which does that and also makes best use of Make's built-in rules, to help when you need to extend it:
src := $(wildcard *.c) test3.c
obj := $(patsubst %.c,%.o,$(src))
CC = gcc
main: $(obj)
$(LINK.c) -o $# $^ $(LDLIBS)
.PHONY: clean
clean:
$(RM) *.o *~

A Makefile with Multiple Executables

I am trying to write a makefile which uses macros to create multiple executables from multiple files at once. I tried searching through previously answered questions but, because I am fairly new to programming in C as well as working with gcc, I was not able to find an answer to my question.
Here is what I have so far:
CC=gcc
CFLAGS=-I.
OBJ = ex1.c ex3.c
EXECUTABLE = ex1 ex3
$(EXECUTABLE): $(OBJ)
gcc -o $# $^ $(CFLAGS)
clean:
rm -f $(EXECUTABLE)
I would like the line
$(EXECUTABLE): $(OBJ)
to create executables ex1 and ex3 from files ex1.c ex3.c respectively.
For this particular case, where each executable has a single source file with .c extension, all you need is a one line Makefile:
all: ex1 ex3
The built-in default rules for make then work already:
$ make
cc -O2 -pipe ex1.c -o ex1
cc -O2 -pipe ex3.c -o ex3
Behind the scene, make is using the POSIXly mandated built-in single suffix rule
.c:
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $<
Vary the command to your liking with make CC=gcc CFLAGS=-O2 LDFLAGS=-s and similar.
Trivia of the day: in fact, if you are willing to name the targets when invoking make, you can use an empty or even run without any Makefile:
$ make -f /dev/null CC=gcc CFLAGS=-O2 LDFLAGS=-s ex1 ex3
gcc -O2 -s ex1.c -o ex1
gcc -O2 -s ex3.c -o ex3
$ rm -f Makefile ex1 ex3
$ make CC=gcc CFLAGS=-O2 LDFLAGS=-s ex1 ex3
gcc -O2 -s ex1.c -o ex1
gcc -O2 -s ex3.c -o ex3
Make magic!
As a rule of thumb, don't reinvent the wheel (or rules), use the rules that are already there. It simplifies your and make's life a lot. This makes for small and sexy makefiles to impress the ladies with :-)
Some suggestions (assuming you use GNU make, not something else)
First, run once make -p, you'll understand what builtin rules make is knowing. Look in particular for COMPILE.c and LINK.c
Then, I suggest
CFLAGS= -g -Wall -I.
(because you really want -g for debugging, and -Wall to get most warnings)
And you probably don't need
$(EXECUTABLE): $(OBJ)
gcc -o $# $^ $(CFLAGS)
However, I suggest adding before most other rules
.PHONY: all clean
all: $(EXECUTABLES)
Actually, I would code your Makefile (for GNU make!) as follow
# file Makefile
CC= gcc
RM= rm -vf
CFLAGS= -Wall -g
CPPFLAGS= -I.
SRCFILES= ex1.c ex2.c ## or perhaps $(wildcard *.c)
OBJFILES= $(patsubst %.c, %.o, $(SRCFILES))
PROGFILES= $(patsubst %.c, %, $(SRCFILES))
.PHONY: all clean
all: $(PROGFILES)
clean:
$(RM) $(OBJFILES) $(PROGFILES) *~
## eof Makefile
Remember that tab is a significant character in Makefile-s (action part of rules). In this answer, lines starting with four spaces at least should really start with a tab character.
Once everything is debugged consider running make clean to clean everything, and then make -j CFLAGS=-O2 all to compile in parallel everything with optimizations.
At last, I recommend using remake and running remake -x to debug complex Makefile-s
Of course, I'm supposing that your directory has only single-file programs.
BTW, there are other build automation tools. Perhaps you might consider using omake or ninja. For building large programs (millions of source code lines) consider also automake, ccache, cmake, icecream. In some cases, consider generating some C code with GPP, GNU bison, SWIG, etc... or using your own Python or Guile script (or C meta-program). See also this draft report.
Don't forget to use a version control system like git for your source files. It is also time to learn such a tool.
The following answer includes multiple executable such as initiate, process1, process2, ..., process4.
LOCAL_INCLUDE=./
all: clean process_first process_second init
process_first:
gcc -g -o process1 -I$(LOCAL_INCLUDE) process1.c -lzmq -L. -L./.
gcc -g -o process2 -I$(LOCAL_INCLUDE) process2.c -lzmq -L. -L./.
process_second:
gcc -g -o process3 -I$(LOCAL_INCLUDE) process3.c -lzmq -L. -L./.
gcc -g -o process4 -I$(LOCAL_INCLUDE) process4.c -lzmq -L. -L./.
init:
gcc -g -o initiate -I$(LOCAL_INCLUDE) initiate.c -lzmq -lconfig -lpthread -L. -L./. -ldl -lrt
clean:
rm -rf init_manager.o init_manager
rm -rf process1 process2 process3 process4
NOTE: It is a good practice to clean and touch all the executable files before making them again.
You're close, but you need a pattern rule:
$(EXECUTABLE): % : %.c
And then a default rule to make it build both:
all: $(EXECUTABLE)

How do I make a simple makefile for gcc on Linux?

I have three files: program.c, program.h and headers.h.
program.c includes program.h and headers.h.
I need to compile this on Linux using gcc compiler. I'm not sure how to do this. Netbeans created one for me, but it's empty.
Interesting, I didn't know make would default to using the C compiler given rules regarding source files.
Anyway, a simple solution that demonstrates simple Makefile concepts would be:
HEADERS = program.h headers.h
default: program
program.o: program.c $(HEADERS)
gcc -c program.c -o program.o
program: program.o
gcc program.o -o program
clean:
-rm -f program.o
-rm -f program
(bear in mind that make requires tab instead of space indentation, so be sure to fix that when copying)
However, to support more C files, you'd have to make new rules for each of them. Thus, to improve:
HEADERS = program.h headers.h
OBJECTS = program.o
default: program
%.o: %.c $(HEADERS)
gcc -c $< -o $#
program: $(OBJECTS)
gcc $(OBJECTS) -o $#
clean:
-rm -f $(OBJECTS)
-rm -f program
I tried to make this as simple as possible by omitting variables like $(CC) and $(CFLAGS) that are usually seen in makefiles. If you're interested in figuring that out, I hope I've given you a good start on that.
Here's the Makefile I like to use for C source. Feel free to use it:
TARGET = prog
LIBS = -lm
CC = gcc
CFLAGS = -g -Wall
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
It uses the wildcard and patsubst features of the make utility to automatically include .c and .h files in the current directory, meaning when you add new code files to your directory, you won't have to update the Makefile. However, if you want to change the name of the generated executable, libraries, or compiler flags, you can just modify the variables.
In either case, don't use autoconf, please. I'm begging you! :)
For example this simple Makefile should be sufficient:
CC=gcc
CFLAGS=-Wall
all: program
program: program.o
program.o: program.c program.h headers.h
clean:
rm -f program program.o
run: program
./program
Note there must be <tab> on the next line after clean and run, not spaces.
UPDATE Comments below applied
all: program
program.o: program.h headers.h
is enough. the rest is implicit
The simplest make file can be
all : test
test : test.o
gcc -o test test.o
test.o : test.c
gcc -c test.c
clean :
rm test *.o
Depending on the number of headers and your development habits, you may want to investigate gccmakedep. This program examines your current directory and adds to the end of the makefile the header dependencies for each .c/cpp file. This is overkill when you have 2 headers and one program file. However, if you have 5+ little test programs and you are editing one of 10 headers, you can then trust make to rebuild exactly those programs which were changed by your modifications.

Determining C executable name

When we are compiling a C program the output is stored in a.out. How can we redirect the compiled output to another file?
Most C compilers provide an option for this, such as the -o option for gcc and some others:
gcc -o gentext gentext.c
cc -o mainprog -Llib -lmymath firstbit.c secondbit.o
xlc -o coredump coredump.c
-ofilename will make filename instead of a.out.
According to the manual:
-o <file> Place the output into <file>
In Unix, where C originated from, C programs are usually compiled module-by-module, and then the compiled modules are linked into an executable. For a project that consists of modules foo.c and bar.c, the commands would be like this:
cc -c foo.c
cc -c bar.c
cc -o myprog foo.o bar.o
(With -c, the output filename becomes the source file with the suffix replaced with .o.)
This allows you to also re-compile only those modules that have changed, which can be a big time saver for big programs, but can also become pretty tricky. (This part is usually automated using make.)
For a single-module program there's not really any point in first compiling to a .o file, and then linking, so a single command suffices:
cc -o foo foo.c
For single-module programs, it is customary to call the resulting executable program the same as the C source file without the .c suffix. For multi-module programs, there is no hard custom on whether the output is named after the file with the main function or not, so you're free to invent whatever strikes your fancy.
With the -o option.
gcc main.c -o myCoolExecutable.o
This is ok if your program consists of a single file. If you have more files I suggest using make: create a Makefile and then run the command make.
A Makefile is a file containing some rules for compilation.
An example can be the following (# means the line is a comment):
CXX = gcc
#CXXFLAGS = -std=c++11
#INC_PATH = ...
#LIBS = ...
SOURCEDIR := yourSourceFolder
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR=$(SOURCEDIR)/obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: yourExecutableName
clean:
$(RM) $(OBJECTS) $(DEPENDS) yourExecutableName
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
yourExecutableName: $(OBJECTS)
$(CXX) $(WARNING) $^ -o $#
#$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) $^ -o $# $(LIBS)
-include $(DEPENDS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CXX) $(WARNING) -MMD -MP -c $< -o $#
Shortly CXX variable defines your compiler (gcc, g++), with CXXFLAGS you can define flags for your compilation (i.e. -std=c++11). Then you can include and define custom (INC_PATH and LIBS: not set in the example). With SOURCEDIR you can specify your source code directory (where *.c files are).Then SOURCES is basically telling that the source files for the compilation are all the files having extension *.c.
The Makefile contains a set of rules whose structure is the following:
output: inputs
commandToExecute
The rule to generate your executable file is
yourExecutableName: $(OBJECTS)
$(CXX) $(WARNING) $^ -o $#
which is equivalent to gcc -Wall -Wextra $(OBJECTS) -o yourExecutableName.
$(OBJECTS) are the object file resulting from the compilation. When the above rule is executed, if they are not found make will continue scanning the file to find a rule to generate them. In this case the rule to generate these files is:
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CXX) $(WARNING) -MMD -MP -c $< -o $#
If further information is needed let me know.
If foo will be your executable and bar.c is your source file then the command is:
gcc -o foo bar.c
Compile using:
cc -o <opfilename> <filename.c>
Execute using:
./<opfilename>
gcc filename.c -o outputfile
This command will directly create an outputfile.exe OR outputfile.out according to operating system. In place of filename.c OR outputfile we can enter path, as shown below.
gcc ./home/user/filename.c -o ./home/outputfile
The format of giving the Name of .exe file according to the User Choice in C Language
step 1 :- Run the gcc (or the compiler you have) in the below format on the Terminal
gcc -o put_your_name_you_want_to_give (space) your_file_name_you_want_to_execute
NB:- If you are Running "Vs Code" Use the 'Tab' key for the Auto completion.
step 2 :- Write down the name of the program in format
.\the_name_you_have_given.exe
you are done!
Assuming you are in ubuntu
step-1: run gcc with these commands to compile filename.c
gcc filename.c -o filename.out
filename.out will be created, (it might or might not be shown where the other files are stored)
step-2: execute the filename.out by
./filename.out
step-3: wait for the output
thats it , you are done

Resources