Common Makefile Templates for Development

Original:

https://blog.csdn.net/qq_20553613/article/details/90649734

Introduction

For development on Windows, many IDEs have integrated compilers, such as Visual Studio, which provides a “one-click compile” feature. After coding is complete, a single operation is all that’s needed to compile, link, and generate the target file.

Linux development differs from Windows. The gcc/g++ compiler is generally used on Linux, and if developing Linux programs for ARM, the arm-linux-gcc/arm-linux-g++ cross-compiler is also needed.

Linux can also achieve a “one-click compile” function, requiring a compilation script called a “Makefile”. Makefiles can be written manually or generated using automated build tools (like scons, CMake). Writing Makefiles manually is one of the distinctions between Linux and Windows programmers. Generally, a universal Makefile can suit most Linux project programs.

3 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 development and debugging, multiple program versions may be generated; a version number can be added after (or before) the target file.

VERSION = 1.00
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)

2. Compiler Choice

On Linux, use gcc/g++; for ARM, use 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

During development, conditional macros are generally added to determine whether specific code should be compiled, such as debug print output code. -D is the identifier, followed by the “macro”.

DEBUG = -DUSE_DEBUG

4. Compilation Options

Compilation conditions can be specified, such as displaying warnings (-Wall) and optimization levels (-O).

CFLAGS = -Wall -O

5. Source Files

Specify the path to the source files, using “wildcard” to get all dependent source files in the path.

SOURCES = $(wildcard ./source/*.c)

6. Header Files

Include the necessary header files, including those for source files and library files.

INCLUDES = -I./include

7. Library File Names

Specify the names of the library files; library files have a fixed format. Static libraries are named libxxx.a; dynamic libraries are named libxxx.so. To specify a library file name, only the “xxx” part needs to be written.

LIB_NAMES = -lfun_a -lfun_so

8. Library File Paths

Specify the storage path for the dependent library files. Note that if a dynamic library is referenced, it may need to be copied to the “/lib” or “/usr/lib” directories, as the system defaults to index dynamic libraries from these paths when executing applications.

LIB_PATH = -L./lib

9. Target Files

Use “patsubst” to compile source files (.c) into target files (.o).

OBJ = $(patsubst %.c, %.o, $(SOURCES))

10. Executable File

Name of the executable file.

TARGET = app

11. Compilation

%.o: %.c
 $(CC) $(INCLUDES) $(DEBUG) $(CFLAGS) $< -o $@

12. Linking

A folder “output” can be created to store the target executable files. After linking, the temporary files (.o) generated during compilation can be deleted.

$(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 remove 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 similar to the “Makefile for Compiling Executable Files”, with the following differences.

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 similar to the “Makefile for Compiling Executable Files”, with the following differences.

1. Compilation options and linking options include the “-fPIC -shared” options. The naming format for dynamic library files is fixed: libxxx.so.

Demo

3.1 Compiling an 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.

Common Makefile Templates for Development

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, “libfun_a.a” and “libfun_so.so”, are stored in the “./lib” directory.

The Makefile is the same as the one in section “2.1”.

Test Run:

Common Makefile Templates for Development

If the executable file indicates that “libfun_so.so” is missing, it must be copied to the root directory’s “/lib” or “/usr/lib” directory, as the system defaults to pulling dynamic libraries from that path when executing programs.

3.2 Generating a Static Library

Write a test routine, the generated library file is the one called by section “3.1” (libfun_a.a). The directory structure is as follows:

Common Makefile Templates for Development

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 one in section “2.2”.

Compile to generate the static library:

Common Makefile Templates for Development

3.3 Generating a Dynamic Library

Write a test routine, the generated library file is the one called by section “3.1” (libfun_so.so). The directory structure is as follows:

Common Makefile Templates for Development

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:

Common Makefile Templates for Development
Recommended Reading Click the title to jump

1. Modern C++ Enumerations

2. IDEs from 30 Years Ago: Only TUI, Background Colors Blinding…

3. How Can Contra Have Such a Long Storyline with Only 128KB?

Leave a Comment