Original: https://blog.csdn.net/qq_20553613/article/details/90649734
Hello everyone, I am ZhengN.
This time I bring you three Makefile templates: compiling executable programs, compiling static libraries, and compiling dynamic libraries.
Related past articles: Overview of Common Makefile Basics!
1. Introduction
For development on Windows, many IDEs integrate compilers, such as Visual Studio, providing a “one-click compile” feature, where after coding, you only need one operation to complete compilation, linking, and generating target files.
Linux development is different from Windows; generally, the gcc/g++ compiler is used under Linux. If developing Linux programs for ARM, you also need to use the arm-linux-gcc/arm-linux-g++ cross-compiler.
A “one-click compile” function can also be achieved under Linux, which requires a build script called “Makefile”. Makefiles can be written manually or generated using automation build tools (like scons, CMake). Writing Makefiles manually is one of the differences between Linux and Windows programmers. Generally, a universal Makefile can suit most Linux project programs.
2. Three Makefile Templates
2.1 Makefile for Compiling Executable Files
VERSION =1.00
CC =gcc
DEBUG =-DUSE_DEBUG
CFLAGS =-Wall
SOURCES =$(wildcard ./source/*.c)
INCLUDES =-I./include
LIB_NAMES =-lfun_a -lfun_so
LIB_PATH =-L./lib
OBJ =$(patsubst %.c, %.o, $(SOURCES))
TARGET =app
#links
$(TARGET):$(OBJ)
@mkdir -p output
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
@rm -rf $(OBJ)
#compile
%.o: %.c
$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $< -o $@
.PHONY:clean
clean:
@echo "Remove linked and compiled files......"
rm -rf $(OBJ) $(TARGET) output
Key Points:
1. Program Version
During the development and debugging process, multiple program versions may be generated. You can add a version number identifier after (or before) the target file.
VERSION = 1.00
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
2. Compiler Selection
For Linux, it is gcc/g++; for ARM it is arm-linux-gcc; the names of customized cross-compilers provided by different CPU manufacturers may vary, such as Hisilicon’s “arm-hisiv300-linux-gcc”.
CC = gcc
3. Macro Definitions
In the development process, special codes generally add macro conditions to choose whether to compile, such as debugging print output codes. -D is the identifier, followed by the “macro”.
DEBUG =-DUSE_DEBUG
4. Compilation Options
You can specify compilation conditions, such as showing warnings (-Wall) and optimization levels (-O).
CFLAGS =-Wall -O
5. Source Files
Specify the source file destination path, using “wildcard” to obtain all dependent source files in the path.
SOURCES =$(wildcard ./source/*.c)
6. Header Files
Include the dependent header files, including the header files for source files and library files.
INCLUDES =-I./include
7. Library File Names
Specify the library file names; library files have a fixed format: static libraries are libxxx.a; dynamic libraries are libxxx.so. You only need to write the “xxx” part to specify the library file name.
LIB_NAMES =-lfun_a -lfun_so
8. Library File Paths
Specify the storage path for dependent library files. Note that if you reference a dynamic library, the dynamic library may be copied to the “/lib” or “/usr/lib” directory. When executing the application, the system defaults to index dynamic libraries from that file.
LIB_PATH =-L./lib
9. Target Files
Use “patsubst” to compile source files (.c) to target files (.o).
OBJ =$(patsubst %.c, %.o, $(SOURCES))
10. Executable Files
Executable file name.
TARGET =app
11. Compilation
%.o: %.c
$(CC) $(INCLUDES) $(DEBUG) $(CFLAGS) $< -o $@
12. Linking
You can create an “output” folder to store the target executable files. After linking and outputting the target executable files, you can delete the temporary files generated during compilation (.o).
$(TARGET):$(OBJ)
@mkdir -p output
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
@rm -rf $(OBJ)
13. Cleaning Compilation Information
Execute “make clean” to clear the temporary files generated during compilation.
.PHONY:clean
clean:
@echo "Remove linked and compiled files......"
rm -rf $(OBJ) $(TARGET) output
2.2 Makefile for Compiling Static Libraries
VERSION =
CC =gcc
DEBUG =
CFLAGS =-Wall
AR =ar
ARFLAGS =rv
SOURCES =$(wildcard *.c)
INCLUDES =-I.
LIB_NAMES =
LIB_PATH =
OBJ =$(patsubst %.c, %.o, $(SOURCES))
TARGET =libfun_a
#link
$(TARGET):$(OBJ)
@mkdir -p output
$(AR) $(ARFLAGS) output/$(TARGET)$(VERSION).a $(OBJ)
@rm -rf $(OBJ)
#compile
%.o: %.c
$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $< -o $@
.PHONY:clean
clean:
@echo "Remove linked and compiled files......"
rm -rf $(OBJ) $(TARGET) output
Key Points:
The basic format is consistent with the “Makefile for Compiling Executable Files”; the differences include the following.
1. Use the “ar” command to link target files (.o) into a static library file (.a). The naming format for static library files is fixed: libxxx.a.
2.3 Makefile for Compiling Dynamic Libraries
VERSION =
CC =gcc
DEBUG =
CFLAGS =-fPIC -shared
LFLAGS =-fPIC -shared
SOURCES =$(wildcard *.c)
INCLUDES =-I.
LIB_NAMES =
LIB_PATH =
OBJ =$(patsubst %.c, %.o, $(SOURCES))
TARGET =libfun_so
#link
$(TARGET):$(OBJ)
@mkdir -p output
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) $(LFLAGS) -o output/$(TARGET)$(VERSION).so
@rm -rf $(OBJ)
#compile
%.o: %.c
$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $< -o $@
.PHONY:clean
clean:
@echo "Remove linked and compiled files......"
rm -rf $(OBJ) $(TARGET) output
Key Points:
The basic format is consistent with the “Makefile for Compiling Executable Files”; the differences include the following.
1. Compilation options and linking options add “-fPIC -shared” options. The naming format for dynamic library files is fixed as libxxx.so.
3. Demo
3.1 Compiling the Application
Write a test routine with the following directory structure: header files are stored in the “include” directory, library files are stored in the “lib” directory, source files are stored in the “source” directory, and the Makefile is in the current directory.

Source Code 1:
/*Header File*/
#ifndef _FUN0_H_
#define _FUN0_H_
#endif
extern void fun0_printf(void);
extern void fun1_printf(void);
/*Source File*/
#include <stdio.h>
#include "fun0.h"
void fun0_printf(void)
{
printf("Call 'fun0'. \r\n");
}
Source Code 2:
/*Header File*/
#ifndef _FUN1_H_
#define _FUN1_H_
#endif
extern void fun1_printf(void);
/*Source File*/
#include <stdio.h>
#include "fun1.h"
void fun1_printf(void)
{
printf("Call 'fun1'.\r\n");
}
Main Function Source Code:
/*Source File*/
#include <stdio.h>
#include "fun0.h"
#include "fun1.h"
#include "fun_lib_a.h"
#include "fun_lib_so.h"
int main(void)
{
#ifdef USE_DEBUG
printf("Debug Application startup.\r\n");
#endif
fun0_printf();
fun1_printf();
fun_lib_a_printf();
fun_lib_so_printf();
return 0;
}
The library files, “./lib” directory, store two library files: a static library libfun_a.a and a dynamic library libfun_so.so.
The Makefile is the same as the template in section “2.1”.
Test Run:

If the executable file prompts that “libfun_so.so” is missing, you need to copy “libfun_so.so” to the “/lib” or “/usr/lib” directory under the root directory, because the system executes programs and defaults to pull dynamic libraries from that path.
3.2 Generating Static Libraries
Write a test routine to produce the library file called by section “3.1” (libfun_a.a). The directory structure is as follows:

Source Code:
/*Header File*/
#ifndef _FUN_LIB_A_H_
#define _FUN_LIB_A_H_
#endif
extern void fun_lib_a_printf(void);
/*Source File*/
#include <stdio.h>
#include "fun_lib_a.h"
void fun_lib_a_printf(void)
{
printf("Call 'fun_lib_a'.\r\n");
}
The Makefile is the same as the template in section “2.2”.
Compile to generate the static library:

3.3 Generating Dynamic Libraries
Write a test routine to produce the library file called by section “3.1” (libfun_so.so). The directory structure is as follows:

Source Code:
/*Header File*/
#ifndef _FUN_LIB_SO_H_
#define _FUN_LIB_SO_H_
#endif
extern void fun_lib_so_printf(void);
/*Source File*/
#include <stdio.h>
#include "fun_lib_so.h"
void fun_lib_so_printf(void)
{
printf("Call 'fun_lib_so'.\r\n");
}
Compile to generate the dynamic library:

Friendly Reminder
Due to recent changes in the WeChat public account’s push rules, if you want to see our articles frequently, you can click “like” or “view” at the bottom of the page after each reading, so that the articles pushed each time will appear in your subscription list promptly.
Disclaimer:This article comes from the internet, conveying knowledge for free, and the copyright belongs to the original author. If there are any copyright issues, please contact me for deletion.
Past Recommendations:
Cross-Platform Build Tool, Is CMake the Best?
Several Very Useful Macro Techniques in C Language and Embedded Systems
Sharing a Self-Used, Minimal Log Module!
Sharing a Very Cool IDE! Essential for Software Engineering
Compilation Techniques in C Language and Embedded Systems
Embedded Mixed Bag Weekly | Issue 1
Hello Series | CMake Basic Knowledge
Essential Content | Project Weakness? Nanopb Can Help You!
Reply 1024 in the public account chat interface to get embedded resources; reply m to view the article summary.
Click Read the Original to see more shares.