General Makefile Application Guide for Advanced Embedded Programming

Introduction

For development on Windows, many IDEs integrate compilers, such as Visual Studio, providing a “one-click compile” feature, allowing the user to compile, link, and generate target files with just one operation after coding.

Linux development differs from Windows; the gcc/g++ compiler is generally used in Linux. If developing Linux programs for ARM, the arm-linux-gcc/arm-linux-g++ cross-compilers must also be utilized.

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

Three Makefile Templates

2.1 Makefile for Compiling Executables

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

The development and debugging process may produce multiple program versions. 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 Selection

On Linux, use gcc/g++; for ARM, use arm-linux-gcc; different CPU vendors provide custom cross-compiler names that may vary, such as Hisilicon’s “arm-hisiv300-linux-gcc.”

CC = gcc

3. Macro Definitions

During development, special code is generally added with macro conditions to decide whether to compile, such as debugging 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) or 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 dependent header files, including source and library files’ headers.

INCLUDES =-I./include

7. Library File Names

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

LIB_NAMES =-lfun_a -lfun_so

8. Library File Paths

Specify the storage path for dependent library files. Note that if a dynamic library is referenced, it may be copied to the “/lib” or “/usr/lib” directory, and the system defaults to indexing dynamic libraries from that path 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

Executable file name.

TARGET =app

11. Compilation

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

12. Linking

Create an “output” folder to store the target executable file. After linking and outputting the target executable file, temporary files generated during compilation (.o) can be deleted.

$(TARGET):$(OBJ)
 @mkdir -p output
 $(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
 @rm -rf $(OBJ)

13. Cleaning Compilation Info

Execute “make clean” to clear 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 Executables,” with the following differences.

1. The “ar” command is used to link target files (.o) into a static library file (.a). The fixed naming format for static library files is: 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 Executables,” with the following differences.

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

Demo

3.1 Compiling Applications

Write a test routine with the following directory structure. Header files are stored in the “include” directory, library files in the “lib” directory, source files in the “source” directory, and the Makefile in the current directory.

General Makefile Application Guide for Advanced Embedded Programming

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");
}
</stdio.h>

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");
}
</stdio.h>

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;
}
</stdio.h>

Library files are stored in the “./lib” directory, with 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:

General Makefile Application Guide for Advanced Embedded Programming

If the executable file indicates that “libfun_so.so” is missing, it needs to be copied to the root directory’s “/lib” or “/usr/lib” directory, as the system executes programs, defaulting to that path for dynamic library linking.

3.2 Generating Static Libraries

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

General Makefile Application Guide for Advanced Embedded Programming

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");
}
</stdio.h>

The Makefile is the same as the template in section “2.2”.

Compile to generate the static library:

General Makefile Application Guide for Advanced Embedded Programming

3.3 Generating Dynamic Libraries

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

General Makefile Application Guide for Advanced Embedded Programming

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");
}
</stdio.h>

Compile to generate the dynamic library:

General Makefile Application Guide for Advanced Embedded Programming

Recommended Practical Insights

AUTOSAR Practical Guide: Information Security Protocol Stack Integration Guide Based on ETAS Toolchain

AUTOSAR Practical Guide: Summary of EcuM Startup Timing

AUTOSAR Practical Guide: Step-by-Step Guide to the Watchdog Protocol Stack

END

General Makefile Application Guide for Advanced Embedded Programming
Click the blue text below to jump

Selected | AUTOSARFull Stack Series

Selected | AUTOSARDictionary Series

Selected | Vehicle Ethernet Learning Guide

Selected | UDS Diagnostic Services All-in-One

Selected | HighTec Compiler User Guide

Selected | Lauterbach User Guide

Selected | XiaoT Technical Articles Collection

End of Article Benefits

1. To obtain XiaoT’s UDS Diagnostic Services Learning Guide (85 pages),

reply with “

UDS Guide

to download for free;

2. To facilitate technical communication, an AUTOSAR Technical Exchange Group has been created for discussing cutting-edge topics such as AP, CP, DDS, SOME/IP. Reply with “Join Group” to join;

Sharing is not easy; if you benefit from it, please thank by clicking 【👍】+【Looking】

Copyright Statement:

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

Copyright belongs to the original author; this is for academic discussion and research purposes. If there are copyright issues, please contact us in time. Thank you!

Leave a Comment