Make files. Building a program with different compilation parameters. Basic make syntax

make is a utility for automatic assembly programs. Allows you to track changes in source code program and not compile the entire project, but only those files that have changed or those that depend on changes made. At large projects this provides significant time savings.

In this post I will try to tell you how to create a makefile.

By default, the build rules are read from a file called Makefile.

The Makefile structure can be represented as follows:

GOAL: DEPENDENCE ACTION

But usually more complex rules are used, for example:

GOAL: GOAL1 GOAL2 ACTION GOAL1: DEPENDENCE1 ACTION1 GOAL2: DEPENDENCE2 ACTION2

GOAL is what we get as a result of ACTION. This could be a file, directory, or simply an abstract TARGET that has no connection with any object on the hard drive. A colon is placed after the target name. When you run the make command without parameters, the first rule found will be executed. To execute another rule, you need to specify it to the make command

Make GOAL2

DEPENDENCE is what our GOAL depends on. These can be files, directories or other TARGETS. Make compares the date and time of change of the GOAL and the objects on which the goal depends. If the objects on which the goal depends were changed later than the goal was created, then an ACTION will be executed. ACTION is also performed if TARGET is not a file or directory name.

AN ACTION is a set of commands that must be executed. Commands must be preceded by a tab character. If spaces are entered instead of a tab character, an error message will be displayed during compilation:

Makefile:13: ***delimiter missing. Stop.

Makefile:13: *** missing separator. Stop.

Example Makefile:

all: test.elf test.elf: test1.o test2.o gcc -o test.elf test1.o test2.o test1.o test1.c gcc -c test1.c -o test1.o test2.o test2.c gcc -c test2.c -o test2.o

Consider the last example:
All is executed first because is at the beginning of the Makefile. all depends on test.elf and there is no file or directory named all, so it will always check the target named test.elf.

test.elf depends on test1.o and test2.o, so the target test1.o will be checked first then test2.o

When checking target test1.o, the modification date and time of file test1.o and test1.c are compared. If the file test1.o does not exist or the file test1.c was modified later than test1.o then the command gcc -c test1.c -o test1.o will be executed.

The target test2.o will be checked in the same way.

After this, the date and time of modification of the test.elf file and the test1.o test2.o files are compared. If test1.o or test2.o is newer then the command gcc -o test.elf test1.o test2.o will be executed

In this way, changes in the files test1.c and test2.c are tracked.

P/S I hope this note will simplify the creation of a makefile, but if you have any questions, write in the comments, I will try to answer.

The utility automatically determines which parts big program the commands to recompile them must be recompiled. Most often make used for compiling C programs and contains features aimed specifically at such tasks, but you can use make with any programming language. Moreover, using the utility make not limited to programs. You can use it to describe any problem where some files must be automatically generated from others whenever they change.

make-file

Before use make, you need to create a file called makefile, which describes the relationships between your program's files and contains commands to update each file. Usually executable file depends on object files, which in turn depend on source files and header files. For name makefile title recommended GNUmakefile, makefile or Makefile, and search is underway exactly in the order listed. If you need to use a non-standard name, you can pass it explicitly using the option -f.
When makefile has already been written, just run the command in the directory in which it is located make. Simple makefile consists of rules (instructions) of the following type:


VARIABLE = VALUE...
GOAL...: DEPENDENCE...
TEAM 1
TEAM 2
VARIABLE = VALUE...
GOAL...: DEPENDENCE...
TEAM 1
TEAM 2

etc.

TARGET usually represents the name of the file generated by the program make; examples of targets are executable or object files. The target can also be the name of the action to perform, such as " clean".
ADDICTION is a file whose modification serves as an indication that the target is needed. Often the target depends on several files.
TEAM- is an action that performs make. A rule can have more than one command, each on its own line. Important Note: You must start each line containing commands with a tab character. Long lines are split into several using backslash followed by a newline. Sharp sign # is the beginning of a comment. Line with # completely ignored. Comments can span multiple lines using a backslash at the end of the line.

Example makefile

Using Default Actions


#default target - file edit
edit: main.o kbd.o command.o display.o \
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

Main.o: main.c defs.h
cc -c main.c
kbd.o: kbd.c defs.h command.h
cc -c kbd.c
command.o: command.c defs.h command.h
cc -c command.c
display.o: display.c defs.h buffer.h
cc -c display.c
insert.o: insert.c defs.h buffer.h
cc -c insert.c
search.o: search.c defs.h buffer.h
cc -c search.c
files.o: files.c defs.h buffer.h command.h
cc -c files.c
utils.o: utils.c defs.h
cc -c utils.c
clean:
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

Default, make starts with the first rule (not counting rules whose target names begin with " . "). It is called main goal default. In our case this is the rule edit. If the file edit newer than the object files it depends on, then nothing will happen. Otherwise, before make be able to fully process this rule, it must recursively process the rules for the files on which it depends " edit". Each of these files is processed according to its own rule. Recompilation must be carried out if the source file or any of header files, mentioned among the dependencies, is updated later than the object file, or if the object file does not exist.
Rule clean does not correspond to any created file and correspondingly, clean It does not depend on anything and is not itself included in the list of dependencies. When launched by default clean will not be called. To execute it, you must explicitly specify the target at startup make - make clean.
Variables and default actions (implicit rules) can be used to shorten the entry

Special Purpose .PHONY is built into make and defines its dependencies as target names that have no corresponding files. If this rule skip, then create a file in the current directory with the name clean will block execution make clean.
Using default rules allows you to change the style of dependency entries:

Square brackets mean that the presence of this part is optional.
Target- the name of the goal to be completed.
Variable ="abc"-redefinition of variables. The values ​​of the variables entered in command line have higher priority than the definitions in makefile.
Options:
-f file- explicit name setting makefile, if the task is omitted, then files are searched GNUmakefile, makefile or Makefile
-n; - imitation of actions without real execution, used for debugging
-t- changing the time of goal modification without actual execution
-q- checking for the need to update the goal without actually executing it

I've always been attracted to minimalism. The idea that one thing should do one thing, but do it as best as possible, resulted in the creation of UNIX. And although UNIX can no longer be called a simple system, and the minimalism in it is not so easy to see, it can be considered a clear example quantity-qualitative transformation of many simple and understandable things into one very complex and opaque one. In its development, make went through approximately the same path: simplicity and clarity, with growing scale, turned into a terrible monster (remember your feelings when you first opened a makefile).

My persistent ignoring of make for a long time was due to the convenience of the IDEs used, and the reluctance to understand this “relic of the past” (essentially laziness). However, all these annoying buttons, menus, etc. the attributes of all kinds of studios forced me to look for an alternative to the method of work that I had been practicing so far. No, I haven't become a make guru, but the knowledge I've gained is quite enough for my small projects. This article is intended for those who, like me just recently, want to break out of the cozy window slavery into the ascetic but free world of the shell.

Make- basic information

make is a utility designed to automate the conversion of files from one form to another. The conversion rules are specified in a script called Makefile, which must be located in the root of the project's working directory. The script itself consists of a set of rules, which in turn are described:

1) goals (what this rule does);
2) details (what is necessary to fulfill the rule and obtain goals);
3) commands (performing these transformations).

IN general view The makefile syntax can be represented as follows:

# Indentation is carried out exclusively using tab characters, # each command must be preceded by an indentation<цели>: <реквизиты> <команда #1> ... <команда #n>

That is, the make rule is the answer to three questions:

(What do we make it from? (details)) ---> [How do we make it? (commands)] ---> (What are we doing? (goals))
It’s easy to see that the translation and compilation processes fit very nicely into this diagram:

(source files) ---> [broadcast] ---> (object files)
(object files) ---> [link] ---> (executable files)

The simplest Makefile

Let's say we have a program consisting of just one file:

/* * main.c */ #include int main() ( printf("Hello World!\n"); return 0; )
To compile it, a very simple makefile is enough:

Hello: main.c gcc -o hello main.c
This Makefile consists of one rule, which in turn consists of a target - “hello”, a prop - “main.c”, and a command - “gcc -o hello main.c”. Now, to compile, just issue the make command in the working directory. By default, make will execute the very first rule if the execution target was not explicitly specified when called:

$make<цель>

Compilation from multiple sources

Let's assume that we have a program consisting of 2 files:
main.c
/* * main.c */ int main() ( hello(); return 0; )
and hello.c
/* * hello.c */ #include void hello() ( printf("Hello World!\n"); )
The Makefile that compiles this program might look like this:

Hello: main.c hello.c gcc -o hello main.c hello.c
It is quite functional, but has one significant drawback: we will reveal which one further.

Incremental compilation

Let's imagine that our program consists of a dozen or two source files. We make changes to one of them and want to rebuild it. Using the approach described in the previous example will result in all source files being compiled again, which will negatively impact recompilation time. The solution is to divide the compilation into two stages: the translation stage and the linking stage.

Now, after changing one of the source files, it is enough to translate it and link all object files. At the same time, we skip the stage of translating details that are not affected by changes, which reduces compilation time overall. This approach is called incremental compilation. To support this, make compares the change times of targets and their details (using data file system), thanks to which it independently decides which rules should be followed and which can simply be ignored:

Main.o: main.c gcc -c -o main.o main.c hello.o: hello.c gcc -c -o hello.o hello.c hello: main.o hello.o gcc -o hello main. o hello.o
Try building this project. To build it, you must explicitly specify the target, i.e. give the command make hello.
Afterwards, change any of the source files and build it again. Please note that during the second compilation, only the modified file will be translated.

Once run, make will try to get the hello target right away, but to create it you need the main.o and hello.o files, which don't exist yet. Therefore, the execution of the rule will be delayed and make will look for rules that describe how to obtain the missing details. Once all the details have been received, make will return to executing the deferred target. This means that make executes the rules recursively.

Fictitious targets

In fact, not only real files can act as make targets. Anyone who has had to build programs from source code should be familiar with two standard commands in the UNIX world:

$ make $ make install
The make command compiles the program, and the make install command installs it. This approach is very convenient, since everything needed to build and deploy the application in target system included in one file (let's forget about the configure script for a moment). Please note that in the first case we do not specify the goal, and in the second the goal is not the creation of the install file at all, but the process of installing the application on the system. So-called fictitious (phony) targets allow us to perform such tricks. Here short list standard goals:

  • all is the default target. You don't have to explicitly specify it when calling make.
  • clean - clear the directory of all files obtained as a result of compilation.
  • install - perform installation
  • uninstall - and uninstallation respectively.
To prevent make from looking for files with such names, they should be defined in the Makefile using the .PHONY directive. The following is an example Makefile with targets all, clean, install and uninstall:

PHONY: all clean install uninstall all: hello clean: rm -rf hello *.o main.o: main.c gcc -c -o main.o main.c hello.o: hello.c gcc -c -o hello. o hello.c hello: main.o hello.o gcc -o hello main.o hello.o install: install ./hello /usr/local/bin uninstall: rm -rf /usr/local/bin/hello
Now we can build our program, install/uninstall it, and also clean out the working directory using standard make targets.

Note that the all target does not specify commands; all she needs is to get the hello props. Knowing about the recursive nature of make, it is not difficult to imagine how this script will work. It should also be noted Special attention on the fact that if the hello file already exists (left after the previous compilation) and its details have not been changed, then the make command nothing will be reassembled. This is a classic make rake. For example, by changing a header file that was accidentally not included in the list of details, you can get long hours headache. Therefore, to guarantee a complete rebuild of the project, you must first clear the working directory:

$ make clean $ make
You will need to use sudo to complete the install/uninstall goals.

Variables

All those who are familiar with the DRY (Don't repeat yourself) rule have probably already noticed something wrong, namely, our Makefile contains big number repeating fragments, which can lead to confusion during subsequent attempts to expand or change it. In imperative languages, we have variables and constants for these purposes; make also has similar facilities. Variables in make are named strings and are defined very simply:

=
There is an unspoken rule that variables should be named in upper case, for example:

SRC = main.c hello.c
This is how we defined the list of source files. To use the value of a variable, it must be dereferenced using the $( construct ); for example like this:

Gcc -o hello $(SRC)
Below is a makefile that uses two variables: TARGET - to determine the name target program and PREFIX - to determine the path to install the program on the system.

TARGET = hello PREFIX = /usr/local/bin .PHONY: all clean install uninstall all: $(TARGET) clean: rm -rf $(TARGET) *.o main.o: main.c gcc -c -o main. o main.c hello.o: hello.c gcc -c -o hello.o hello.c $(TARGET): main.o hello.o gcc -o $(TARGET) main.o hello.o install: install $ (TARGET) $(PREFIX) uninstall: rm -rf $(PREFIX)/$(TARGET)
This is already prettier. I think now the above example does not need any special comments for you.

Automatic Variables

Automatic variables are intended to simplify makefiles, but in my opinion have a negative impact on their readability. Be that as it may, I will list here a few of the most commonly used variables, and what to do with them (or whether to do it at all) is up to you:
  • $@ Target name of the rule being processed
  • $< Имя первой зависимости обрабатываемого правила
  • $^ List of all dependencies of the processed rule
If anyone wants to completely obfuscate their scripts, you can get inspiration here:

I've always been attracted to minimalism. The idea that one thing should do one thing, but do it as best as possible, resulted in the creation of UNIX. And although UNIX can no longer be called a simple system, and minimalism in it is not so easy to see, it can be considered a clear example of the quantitative and qualitative transformation of many simple and understandable things into one very complex and opaque one. In its development, make went through approximately the same path: simplicity and clarity, with increasing scale, turned into a terrible monster (remember your feelings when you first opened a makefile).

My persistent ignoring of make for a long time was due to the convenience of the IDEs used, and the reluctance to understand this “relic of the past” (essentially laziness). However, all these annoying buttons, menus, etc. the attributes of all kinds of studios forced me to look for an alternative to the method of work that I had been practicing so far. No, I haven't become a make guru, but the knowledge I've gained is quite enough for my small projects. This article is intended for those who, like me just recently, want to break out of the cozy window slavery into the ascetic but free world of the shell.

Make- basic information

make is a utility designed to automate the conversion of files from one form to another. The conversion rules are specified in a script called Makefile, which must be located in the root of the project's working directory. The script itself consists of a set of rules, which in turn are described:

1) goals (what this rule does);
2) details (what is necessary to fulfill the rule and obtain goals);
3) commands (performing these transformations).

In general, the makefile syntax can be represented as follows:

# Indentation is carried out exclusively using tab characters, # each command must be preceded by an indentation<цели>: <реквизиты> <команда #1> ... <команда #n>

That is, the make rule is the answer to three questions:

(What do we make it from? (details)) ---> [How do we make it? (commands)] ---> (What are we doing? (goals))
It’s easy to see that the translation and compilation processes fit very nicely into this diagram:

(source files) ---> [broadcast] ---> (object files)
(object files) ---> [link] ---> (executable files)

The simplest Makefile

Let's say we have a program consisting of just one file:

/* * main.c */ #include int main() ( printf("Hello World!\n"); return 0; )
To compile it, a very simple makefile is enough:

Hello: main.c gcc -o hello main.c
This Makefile consists of one rule, which in turn consists of a target - “hello”, a prop - “main.c”, and a command - “gcc -o hello main.c”. Now, to compile, just issue the make command in the working directory. By default, make will execute the very first rule if the execution target was not explicitly specified when called:

$make<цель>

Compilation from multiple sources

Let's assume that we have a program consisting of 2 files:
main.c
/* * main.c */ int main() ( hello(); return 0; )
and hello.c
/* * hello.c */ #include void hello() ( printf("Hello World!\n"); )
The Makefile that compiles this program might look like this:

Hello: main.c hello.c gcc -o hello main.c hello.c
It is quite functional, but has one significant drawback: we will reveal which one further.

Incremental compilation

Let's imagine that our program consists of a dozen or two source files. We make changes to one of them and want to rebuild it. Using the approach described in the previous example will result in all source files being compiled again, which will negatively impact recompilation time. The solution is to divide the compilation into two stages: the translation stage and the linking stage.

Now, after changing one of the source files, it is enough to translate it and link all object files. At the same time, we skip the stage of translating details that are not affected by changes, which reduces compilation time overall. This approach is called incremental compilation. To support it, make compares the change time of targets and their details (using file system data), thanks to which it independently decides which rules should be executed and which can simply be ignored:

Main.o: main.c gcc -c -o main.o main.c hello.o: hello.c gcc -c -o hello.o hello.c hello: main.o hello.o gcc -o hello main. o hello.o
Try building this project. To build it, you must explicitly specify the target, i.e. give the command make hello.
Afterwards, change any of the source files and build it again. Please note that during the second compilation, only the modified file will be translated.

Once run, make will try to get the hello target right away, but to create it you need the main.o and hello.o files, which don't exist yet. Therefore, the execution of the rule will be delayed and make will look for rules that describe how to obtain the missing details. Once all the details have been received, make will return to executing the deferred target. This means that make executes the rules recursively.

Fictitious targets

In fact, not only real files can act as make targets. Anyone who has had to build programs from source code should be familiar with two standard commands in the UNIX world:

$ make $ make install
The make command compiles the program, and the make install command installs it. This approach is very convenient because everything needed to build and deploy the application on the target system is included in one file (let's forget about the configure script for a moment). Please note that in the first case we do not specify the goal, and in the second the goal is not the creation of the install file at all, but the process of installing the application on the system. So-called fictitious (phony) goals allow us to perform such tricks. Here is a short list of standard goals:

  • all is the default target. You don't have to explicitly specify it when calling make.
  • clean - clear the directory of all files obtained as a result of compilation.
  • install - perform installation
  • uninstall - and uninstallation respectively.
To prevent make from looking for files with such names, they should be defined in the Makefile using the .PHONY directive. The following is an example Makefile with targets all, clean, install and uninstall:

PHONY: all clean install uninstall all: hello clean: rm -rf hello *.o main.o: main.c gcc -c -o main.o main.c hello.o: hello.c gcc -c -o hello. o hello.c hello: main.o hello.o gcc -o hello main.o hello.o install: install ./hello /usr/local/bin uninstall: rm -rf /usr/local/bin/hello
Now we can build our program, install/uninstall it, and also clean out the working directory using standard make targets.

Note that there are no commands specified in the all target; all she needs is to get the hello props. Knowing about the recursive nature of make, it is not difficult to imagine how this script will work. You should also pay special attention to the fact that if the hello file already exists (left after the previous compilation) and its details have not been changed, then the make command nothing will be reassembled. This is a classic make rake. For example, changing a header file that is accidentally not included in the list of details can result in many hours of headaches. Therefore, to guarantee a complete rebuild of the project, you must first clear the working directory:

$ make clean $ make
You will need to use sudo to complete the install/uninstall goals.

Variables

All those who are familiar with the DRY (Don't repeat yourself) rule have probably already noticed something is wrong, namely, our Makefile contains a large number of repeated fragments, which can lead to confusion in subsequent attempts to expand or change it. In imperative languages ​​for these For purposes of this, we have variables and constants; make also has similar facilities. Variables in make are named strings and are defined very simply:

=
There is an unspoken rule that variables should be named in upper case, for example:

SRC = main.c hello.c
This is how we defined the list of source files. To use the value of a variable, it must be dereferenced using the $( construct ); for example like this:

Gcc -o hello $(SRC)
Below is a makefile that uses two variables: TARGET - to determine the name of the target program and PREFIX - to determine the path to install the program on the system.

TARGET = hello PREFIX = /usr/local/bin .PHONY: all clean install uninstall all: $(TARGET) clean: rm -rf $(TARGET) *.o main.o: main.c gcc -c -o main. o main.c hello.o: hello.c gcc -c -o hello.o hello.c $(TARGET): main.o hello.o gcc -o $(TARGET) main.o hello.o install: install $ (TARGET) $(PREFIX) uninstall: rm -rf $(PREFIX)/$(TARGET)
This is already prettier. I think now the above example does not need any special comments for you.

Automatic Variables

Automatic variables are intended to simplify makefiles, but in my opinion have a negative impact on their readability. Be that as it may, I will list here a few of the most commonly used variables, and what to do with them (or whether to do it at all) is up to you:
  • $@ Target name of the rule being processed
  • $< Имя первой зависимости обрабатываемого правила
  • $^ List of all dependencies of the processed rule
If anyone wants to completely obfuscate their scripts, you can get inspiration here:

This article is a short tutorial on creating Makefiles. It explains what a Makefile is for and gives a few rules to follow when creating one.

Introduction

Let's say you are developing a program called foo, consisting of five header files - 1.h, 2.h, 3.h, 4.h and - 5.h, and six files with the source code of the program in C - 1.cpp, 2.cpp, 3.cpp, 4.cpp, 5.cpp and main.cpp. (I would like to note that in real projects this style of file naming should be avoided.)

Now let's imagine that you discovered a bug in the 2.cpp file and fixed it. Next, to get a corrected version of the program, you compile all the files included in the project, although the changes affected only one file. This leads to wasted time, especially if the computer is not very fast.

Is there a solution to the problem?

No need to worry, my friends! This problem has been resolved a long time ago. Experienced programmers developed the make utility. Instead of recompiling all the files with source texts, it processes only those files that have undergone changes. In our case, only one file will be compiled - 2.cpp. Is not that great!?

  • The make utility makes life a lot easier when you need to run long, complex commands to build a project.
  • A project sometimes requires setting rarely used and therefore difficult to remember compiler options. make will save you the trouble of keeping them in memory.
  • Uniformity, because Working with this utility is supported by many development environments.
  • The build process can be automated because make can be called from scripts or from cron.

What is the Makefile for?

Despite all its advantages, the make utility does not know anything about our project, so we need to create a simple text file which will contain everything necessary instructions on assembly. The file with instructions for assembling the project is called makefile (pronounced "makefile")approx. translation) .

Typically these files are named makefile or Makefile, following naming conventions for such files. If you give the instruction file a different name, you will need to call make with the -f option.

For example, if you named your makefile bejo , then the command to build the project will look like this:

Make -f bejo

File structure

Makefile contains sections for "goals", dependencies And rules assemblies. All this is formatted as follows: first the name of the target is specified (usually the name of the executable or object file), followed by a colon, then the names of the dependencies, i.e. files necessary to achieve this goal. Finally, there is a list of rules: i.e. commands that must be executed to obtain the specified goal.

A simple example of a makefile structure:

Target: dependencies command command ...

Every command rule must begin with a tab character -- this required condition! Missing a tab character at the beginning of a rule line is the most common mistake. Fortunately, such errors are easy to detect because make reports them.

Makefile example.

Below is a simple example (line numbers added for clarity).

1 client: conn.o 2g++ client.cpp conn.o -o client 3 conn.o: conn.cpp conn.h 4g++ -c conn.cpp -o conn.o

In this example, the line containing the text
client:conn.o ,
is called a "dependency line" and the line
g++ client.cpp conn.o -o client
is called a "rule" and describes the action to be performed.

And now in more detail about the example given above:

  • The target is set to the client executable file, which depends on the conn.o object file
  • Rule for assembling a given target
  • The third line specifies the target conn.o and the files it depends on, conn.cpp and conn.h.
  • The fourth line describes the action to build the conn.o target.

Comments

Lines starting with "#" are comments

Below is an example makefile with comments:

1 # Create an executable file "client" 2 client: conn.o 3g++ client.cpp conn.o -o client 4 5 # Create object file "conn.o" 6 conn.o: conn.cpp conn.h 7g++ -c conn.cpp -o conn.o

"False" target

Typically, "dummy" targets, which represent an "imaginary" target file name, are used when conflicts arise between target names and file names when the target name is explicitly specified on the command line.

Let's say there is a rule in the makefile that does not create anything, for example:

Clean: rm *.o temp

Since the rm command does not create a file named clean , such a file will never exist and therefore the make clean command will always run.

However, this rule will not work if there is a file named clean in the current directory. Since the clean target has no dependencies, it will never be considered deprecated and therefore the "rm *.o temp" command will never be executed. (when run, make checks the modification dates of the target file and those files on which it depends. And if the target turns out to be “older,” then make executes the corresponding command rules - editor’s note) For elimination similar problems and there is a special .PHONY declaration declaring a "false" target. For example:

PHONY: clean

Thus, we indicate the need to execute the goal, when explicitly specifying it, in the form of make clean, regardless of whether a file with that name exists or not.

Variables

You can define a variable in a makefile like this:

$VAR_NAME=value

By convention, variable names are in upper case:

$OBJECTS=main.o test.o

To get the value of a variable, you need to enclose its name in round brackets and precede them with a "$" symbol, for example:

$(VAR_NAME)

There are two types of variables in makefiles: "simply calculated" And "recursively calculated".

TOPDIR=/home/tedi/project SRCDIR=$(TOPDIR)/src

When accessing the SRCDIR variable, you will get the value /home/tedi/project/src .

However, recursive variables may not always be evaluated, such as the following definitions:

CC = gcc -o CC = $(CC) -O2

will result in an endless cycle. To solve this problem, you should use "simplified calculated" variables:

CC:= gcc -o CC += $(CC) -O2

Where the ":=" symbol creates a CC variable and assigns it the value "gcc -o". And the "+=" symbol adds "-O2" to the value of the CC variable.

Conclusion

I hope it is quick guide contains enough information to start creating your makefiles. And for this - success in your work.

Bibliography

  • 1 GNU Make Documentation File, info make.
  • Kurt Wall, et al. Linux Programming Unleashed(Programming for Linux in the operational space - editor's note) , 2001.