Sharing Common Makefile Templates

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.

Sharing Common Makefile Templates

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:

Sharing Common Makefile Templates

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:

Sharing Common Makefile Templates

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:

Sharing Common Makefile Templates

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:

Sharing Common Makefile Templates

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:

Sharing Common Makefile Templates

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.

Leave a Comment