See what "Make" is in other dictionaries. Using variables and comments. More advanced uses of MAKE

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 start 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 it depends on" edit". Each of these files is processed according to its own rule. Recompilation must be carried out if the source file or any of the 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

make is a utility for automatic assembly programs. Allows you to track changes in the source code of the program and compile not 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 GOAL 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.

Origin

Before the creation of make, build systems (compilations) of Unix software typically consisted of shell build scripts that accompanied source programs.

make was created by Stuart Feldman ( Stuart Feldman) in 1977 at Bell Labs.

There are many dependency tracking utilities available today, but make is one of the most widely used, primarily due to the fact that it has been included in Unix since the PWB/UNIX version ( for Programmer's Workbench), which contained tools for software development.

Modern versions

There are several versions of make, based on the original make or written from scratch, using the same file formats and basic principles and algorithms, as well as containing some improvements and extensions. For example:

  • BSD make, based on the work of Adam de Boer ( Adam de Boor) over the make version, with the ability to build in parallel; migrated in one form or another to FreeBSD, NetBSD and OpenBSD.
  • GNU make is included with most GNU/Linux distributions and is often used in conjunction with the GNU build system.
$ make love Not war. $ uname -r 7.1-RELEASE-p3

Make file

The make program executes commands according to the rules in special file. This file is called a makefile. Typically, a makefile describes how a program should be compiled and linked.

A makefile consists of rules and variables. The rules have the following syntax:

Goal1 goal2 ...: prop1 prop2... team1 team2...

Rule is a set of commands, the execution of which will lead to the assembly of files - goals from files- props.

The rule tells make that the files produced by the commands ( goals) are dependent on the corresponding prop files. make does not check or use the contents of prop files in any way, however, specifying a list of prop files is only required so that make can verify the presence of these files before running commands and to track dependencies between files.

Usually the target is the name of the file that is generated as a result of the operation specified commands. A target can also be the name of some action that will be performed as a result of executing commands (for example, the clean target in makefiles for compiling programs typically removes all files created during the compilation process).

Lines containing teams, must begin with a tab character.

Let's look at a simple C program. Let the program program consist of a pair of code files - main.c and lib.c, as well as one header file- defines.h, which is included in both code files. Therefore, to create a program, you need to create object files main.o and lib.o from pairs (main.c defines.h) and (lib.c defines.h), and then link them into program. When assembling manually, you need to give the following commands:

Cc -c main.c defines.h cc -c lib.c defines.h cc -o program main.o lib.o

If changes are made to the defines.h file during program development, both files will need to be recompiled and linked, and if lib.c is changed, main.o may not need to be recompiled.

Thus, for each file that we must obtain during the compilation process, we need to indicate on the basis of which files and using which command it is created. The make program, based on this data, does the following:

  • collects from this information the correct sequence of commands to obtain the required result files;
  • and initiates the creation of the required file only if such a file does not exist, or is older than the files on which it depends.

If you do not explicitly specify a target when you run make, the first target in the makefile that does not begin with a "." will be processed.

For program just write the following makefile:

Program: main.o lib.o cc -o program main.o lib.o main.o lib.o: defines.h

A number of features are worth noting. The name of the second target specifies two files and does not specify a compilation command for the same target. In addition, the dependence of object files on “*.c” files is not explicitly stated anywhere. The fact is that the make program has predefined rules for obtaining files with certain extensions. So, for a target object file (extension “.o”), when a corresponding file with extension “.c” is detected, the “cc -c” compiler will be called, indicating this “.c” file and all dependency files in the parameters.

The syntax for defining variables is:

Variable = value

Meaning can be an arbitrary sequence of characters, including spaces and accesses to the values ​​of other variables. With that said, we can modify our makefile as follows:

OBJ = main.o lib.o program: $(OBJ) cc -o program $(OBJ) $(OBJ): defines.h

It should be noted that the calculation of the value of variables occurs only at the time of use (so-called lazy calculation is used). For example, when building the all target from the following makefile, the string “Huh?” will be printed to the screen.

Foo = $(bar) bar = $(ugh) ugh = Huh? all: echo $(foo)

Lib.o: lib.h

Thus, one target file can be specified for multiple purposes. Wherein full list dependencies for a file will be compiled from the dependency lists of all targets in which it participates, the file will be created only once.

see also

Links

  • GNU make manual at gnu.org
  • GNU make manual (version 3.79) (Russian)
  • FreeBSD make manual
  • Troubleshooting problems with ./configure , make , and make install commands
  • Using GNU make (Russian)
  • Effective use of GNU Make (Russian)
  • Help for creating a Makefile (Russian)

Wikimedia Foundation.

  • 2010.
  • Haller, Lev Mikhailovich

Camargue (horse)

    make See what "Make" is in other dictionaries: - make, v. t. d); p. pr. &vb. n. (making).] 1. To cause to…

    make The Collaborative International Dictionary of English

    - make1vt. made, making 1. to bring into being; specif., a) to form by shaping or... ... English World dictionary Make

    - make1vt. made, making 1. to bring into being; specif., a) to form by shaping or... ... English World dictionary- (engl. machen, erstellen) ist ein Computerprogramm, das Shellskript ähnlich Kommandos in Abhängigkeit von Bedingungen ausführt. Es wird hauptsächlich bei der Softwareentwicklung eingesetzt. Genutzt wird es beispielsweise, um in einem Projekt, das … Deutsch Wikipedia

    make- Cet article a pour sujet le logiciel intitulé make. Pour une définition du mot "make", voir l'article make du Wiktionnaire. make est un logiciel traditionnel d UNIX. C est un “moteur de production”: il sert à appeler … Wikipédia en Français

At one time, I really missed such a manual for understanding basic things about make. I think it will be interesting to at least someone. Although this technology is dying out, it is still used in many projects. There wasn’t enough karma for the “Translations” hub, as soon as the opportunity arises, I’ll add it there too. Added to Translations. If there are errors in the design, please point them out. I will fix it.

The article will be of interest primarily to those studying programming in C/C++ in UNIX-like systems from the very roots, without using an IDE.

Compiling a project by hand is a very tedious task, especially when there are more than one source files, and for each of them you need to enter compilation and linking commands every time. But it is not all that bad. Now we will learn how to create and use Makefiles. Makefile is a set of instructions for make programs, which helps to assemble a software project literally in one touch.

To practice, you will need to create a microscopic project a la Hello World from four files in one directory:

main.cpp

#include #include "functions.h" using namespace std; int main())( print_hello(); cout<< endl; cout << "The factorial of 5 is " << factorial(5) << endl; return 0; }


hello.cpp

#include #include "functions.h" using namespace std; void print_hello())( cout<< "Hello World!"; }


factorial.cpp

#include "functions.h" int factorial(int n)( if(n!=1)( return(n * factorial(n-1)); ) else return 1; )


functions.h

void print_hello(); int factorial(int n);


You can download everything in bulk from here
The author used the C++ language, which is not at all necessary to know, and the g++ compiler from gcc. Any other compiler will most likely work too. The files are slightly corrected so that they are compiled with gcc 4.7.1
make program
If you run
make
then the program will try to find a file with the default name Makefile in the current directory and execute instructions from it. If there are several makefiles in the current directory, you can point to the one you need like this:
make -f MyMakefile
There are many other parameters that we don’t need yet. You can find out about them in the man page.
Build process
The compiler takes the source code files and produces object files from them. The linker then takes the object files and produces an executable from them. Assembly = compilation + linking.
Compilation by hand
The easiest way to build the program:
g++ main.cpp hello.cpp factorial.cpp -o hello
It’s inconvenient to type this every time, so we’ll automate it.
The simplest Makefile
It should contain the following parts:
target: dependencies team
For our example, the makefile will look like this:
all: g++ main.cpp hello.cpp factorial.cpp -o hello
Please note that the command line must begin with a tab! Save this as Makefile-1 in your project directory and run the build with make -f Makefile-1
In the first example the target is called all . This is the default target for the makefile and will be executed if no other target is explicitly specified. Also, this target in this example has no dependencies, so make immediately starts executing the desired command. And the command, in turn, launches the compiler.
Using dependencies
Using multiple targets in one makefile is useful for large projects. This is due to the fact that if you change one file, you will not need to rebuild the entire project, but you can get by with rebuilding only the changed part. Example:
all: hello hello: main.o factorial.o hello.o g++ main.o factorial.o hello.o -o hello main.o: main.cpp g++ -c main.cpp factorial.o: factorial.cpp g++ -c factorial.cpp hello.o: hello.cpp g++ -c hello.cpp clean: rm -rf *.o hello
This should be saved under the name Makefile-2 all in the same directory

Now the all target only has a dependency, but no command. In this case, when called, make will sequentially execute all the dependencies specified in the file for this target.
A new goal, clean , has also been added. It is traditionally used to quickly clean up all the build results of a project. Cleanup is started like this: make -f Makefile-2 clean

Using Variables and Comments
Variables are widely used in makefiles. For example, this is a convenient way to take into account the possibility that the project will be compiled with a different compiler or with different options.
# This is a comment that says the CC variable specifies the compiler used to build CC=g++ # This is another comment. He explains that the CFLAGS variable contains flags that are passed to the compiler CFLAGS=-c -Wall all: hello hello: main.o factorial.o hello.o $(CC) main.o factorial.o hello.o -o hello main .o: main.cpp $(CC) $(CFLAGS) main.cpp factorial.o: factorial.cpp $(CC) $(CFLAGS) factorial.cpp hello.o: hello.cpp $(CC) $(CFLAGS) hello.cpp clean: rm -rf *.o hello
This is Makefile-3
Variables are a very convenient thing. To use them, you simply assign them a value before using them. After that, you can substitute their value in the right place in this way: $(VAR)
What to do next
After this brief instruction, you can already try to create simple makefiles yourself. Next you need to read serious textbooks and manuals. As a final chord, you can try to disassemble it yourself and realize such a universal makefile, which can be adapted to almost any project in two touches:
CC=g++ CFLAGS=-c -Wall LDFLAGS= SOURCES=main.cpp hello.cpp factorial.cpp OBJECTS=$(SOURCES:.cpp=.o) EXECUTABLE=hello all: $(SOURCES) $(EXECUTABLE) $(EXECUTABLE ): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o $@ .cpp.o: $(CC) $(CFLAGS) $< -o $@
Makefile-4
Good luck!

Writing a makefile can sometimes become a headache. However, if you figure it out, everything falls into place, and writing a powerful 40-line makefile for any large project can be done quickly and elegantly.

Attention! Basic knowledge of the GNU make utility is assumed.

We have a typical abstract project with the following directory structure:

Let's use something like #include to include header files in the sources , that is, the project/include directory is made standard during compilation.

After assembly it should look like this:

That is, the bin directory contains the working (application) and debug (application_debug) versions, in the Release and Debug subdirectories of the project/obj directory the structure of the project/src directory is repeated with the corresponding source codes of the object files, from which the contents of the bin directory are compiled.

To achieve this effect, create a Makefile in the project directory with the following content:

  1. root_include_dir:= include
  2. root_source_dir:= src
  3. source_subdirs:= . dir1 dir2
  4. compile_flags:= -Wall -MD -pipe
  5. link_flags:= -s -pipe
  6. libraries:= -ldl
  7. relative_include_dirs:= $(addprefix ../ ../ , $(root_include_dir) )
  8. relative_source_dirs:= $(addprefix ../ ../ $(root_source_dir) / , $(source_subdirs) )
  9. objects_dirs:= $(addprefix $(root_source_dir) / , $(source_subdirs) )
  10. objects:= $(patsubst ../ ../% , % , $(wildcard $(addsuffix /* .c* , $(relative_source_dirs) ) ) )
  11. objects:= $(objects:.cpp=.o)
  12. objects:= $(objects:.c=.o)
  13. all: $(program_name)
  14. $(program_name) : obj_dirs $(objects)
  15. g++ -o $@ $(objects) $(link_flags) $(libraries)
  16. obj_dirs:
  17. mkdir -p $(objects_dirs)
  18. VPATH:= ../ ../
  19. %.o: %.cpp
  20. g++ -o $@ -c $< $(compile_flags) $(build_flags) $(addprefix -I, $(relative_include_dirs) )
  21. %.o: %.c
  22. g++ -o $@ -c $< $(compile_flags) $(build_flags) $(addprefix -I, $(relative_include_dirs) )
  23. .PHONY: clean
  24. clean:
  25. rm -rf bin obj
  26. include $(wildcard $(addsuffix /* .d, $(objects_dirs) ) )

In its pure form, such a makefile is only useful for achieving the clean goal, which will remove the bin and obj directories.
Let's add another script called Release to build the working version:

Mkdir -p bin mkdir -p obj mkdir -p obj/Release make --directory=./obj/Release --makefile=../../Makefile build_flags="-O2 -fomit-frame-pointer" program_name=. ./../bin/application

And another Debug script to build the debug version:

Mkdir -p bin mkdir -p obj mkdir -p obj/Debug make --directory=./obj/Debug --makefile=../../Makefile build_flags="-O0 -g3 -D_DEBUG" program_name=../ ../bin/application_debug

Calling one of them will assemble our project into a working or debugging version. And now, first things first.

Let's say we need to build a debug version. Go to the project directory and call ./Debug. The first three lines create the directories. In the fourth line, the make utility is informed that the current directory at startup should be project/obj/Debug, in relation to this, the path to the makefile is then passed and two constants are set: build_flags (compilation flags important for the debug version are listed here) and program_name (for the debug version - this is application_debug).

1: A variable is declared with the name of the root directory of the header files.

2: A variable is declared with the name of the source root directory.

3: A variable with the names of subdirectories of the root source directory is declared.

4: A variable with general compilation flags is declared. -MD forces the compiler to generate a dependency file of the same name with the extension .d for each source. Each such file looks like a rule, where the target is the source name, and the dependencies are all the source and header files that it includes with the #include directive. The -pipe flag forces the compiler to use IPC instead of the filesystem, which speeds up compilation somewhat.

5: A variable with general layout flags is declared. -s forces the linker to remove sections .symtab, .strtab and a bunch of other sections with names like .debug* from the resulting ELF file, which significantly reduces its size. For better debugging purposes, this key can be removed.

6: A variable is declared with the names of the libraries used as link keys.

8: A variable is declared containing the relative names of the directories with standard header files. Then such names are directly passed to the compiler, preceded by the -I switch. For our case, it will be ../../include, because we have only one such directory. The addprefix function adds its first argument to all targets specified by the second argument.

9: A variable is declared containing the relative names of all subdirectories of the root source directory. As a result, we get: ../../src/. ../../src/dir1 ../../src/dir1.

10: A variable is declared containing the names of the subdirectories of the project/obj/Debug/src directory relative to the current project/obj/Debug. That is, with this we list a copy of the project/src directory structure. As a result, we get: /src/dir1 src/dir2.

11: A variable is declared containing the names of the sources found based on the *.c* files (.cpp\.c) of the same name, regardless of the current directory. Let's look at it step by step: the result of addsuffix will be ../../src/./*.с* ../../src/dir1/*.с* ../../src/dir2/*.с*. The wildcard function will expand patterns with asterisks to real file names: ../../src/./main.сpp ../../src/dir1/file1.с../../src/dir1/file2.сpp ../../src/dir2/file3.с../../src/dir2/file4.с. The patsubsb function will remove the ../../ prefix from filenames (it replaces the pattern given in the first argument with the pattern in the second argument, and % represents any number of characters). As a result, we get: src/./main.сpp src/dir1/file1.с src/dir1/file2.сpp src/dir2/file3.с src/dir2/file4.с.

12: In the variable with the names of the extension sources, .cpp is replaced by .o.

13: In the variable with the names of the extension sources, .c is replaced by .o.

15: The first rule announced - its goal becomes the goal of the entire project. The dependency is a constant containing the name of the program (../../bin/application_debug we passed it when we ran make from the script).

17: Description of the key goal. The dependencies are also obvious: the presence of created subdirectories in project/obj/Debug, repeating the structure of the project/src directory and many object files in them.

18: The action of linking object files into a target is described.

20: Rule where the target is the project/obj/Debug/src directory and its subdirectories.

21: The action to achieve the goal is to create the appropriate directories src/., src/dir1 and src/dir2. The -p switch of the mkdir utility ignores the error if, when creating a directory, it already exists.

23: The variable VPATH takes the value ../../. This is required for the following rule templates.

25: Describes a set of rules whose targets are any targets that match the pattern %.o (that is, whose names end in .o), and whose dependencies are targets of the same name that match the pattern %.cpp (that is, whose names end in .cpp). In this case, the same name is understood not only as an exact match, but also if the dependency name is preceded by the contents of the VPATH variable. For example, the names src/dir1/file2 and ../../src/dir1/file2 will match because the VPATH contains ../../.

26: Calling the compiler to turn the C++ source into an object file.

28: Describes a set of rules whose targets are any targets that match the pattern %.o (that is, whose names end in .o), and whose dependencies are targets of the same name that match the pattern %.c (that is, whose names end in .c). Same name as in line 23.

29: Calling the compiler to turn the C source into an object file.

31: Some goal clean is declared abstract. Achieving an abstract goal always occurs and does not depend on the existence of a file of the same name.

32: Declaration of the abstract goal clean.

33: The action to achieve this is to destroy the project/bin and project/obj directories with all their contents.

36: Includes the contents of all dependency files (with a .d extension) located in subdirectories of the current directory. The make utility performs this action at the beginning of parsing the makefile. However, dependency files are created only after compilation. This means that during the first build, not a single such file will be included. But it's not scary. The purpose of including these files is to force a recompilation of sources that depend on the modified header file. On the second and subsequent builds, make will include the rules described in all dependency files and, if necessary, achieve all targets that depend on the modified header file.