Universal Makefile Templates for Development

Universal Makefile Templates for Development

Introduction

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

Linux development differs from Windows; on Linux, the gcc/g++ compiler is typically used. If developing Linux programs for ARM, the arm-linux-gcc/arm-linux-g++ cross-compiler is needed.

Linux can also achieve a “one-click compile” function, which requires a compilation script called a “Makefile”. Makefiles can be written manually or generated using automation build tools (like scons, CMake). Writing Makefiles manually distinguishes Linux programmers from Windows programmers; generally, a universal Makefile can be suitable for 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

Multiple program versions may be generated during the development and debugging process. A version number identifier can be added to the target file.

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

2. Compiler Selection

Use gcc/g++ on Linux; arm-linux-gcc for ARM; the names of customized cross-compilers may vary by CPU vendor, such as Hisilicon’s “arm-hisiv300-linux-gcc”.

CC = gcc

3. Macro Definitions

During development, special code is generally added with macro conditions to choose 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) and optimization levels (-O).

CFLAGS =-Wall -O

5. Source Files

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

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

6. Header Files

Include dependent header files, including the header files of source files and library files.

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 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 of dependent library files. Note that if a dynamic library is referenced, it may be copied to the “/lib” or “/usr/lib” directory. When executing an application, the system defaults to indexing dynamic libraries from this path.

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 Files

The name of the executable file.

TARGET =app

11. Compilation

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

12. Linking

Creates an “output” folder to store the target executable file. After linking, the output target executable file can delete the temporary files (.o) generated during compilation.

$(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 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. The “ar” command is used to link target files (.o) into a static library file (.a). Static library files have a fixed naming format: 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 include the “-fPIC -shared” options. Dynamic library files have a fixed naming format of libxxx.so.

Demo

3.1 Compile the Application

Write a test routine, with the file storage directory structure as follows: 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.

Universal 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");
}
</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, two library files are stored in the “./lib” directory, one static library libfun_a.a and one dynamic library libfun_so.so.

The Makefile file is the “Makefile for Compiling Executable Files” template from section 2.1.

Test Run:

Universal Makefile Templates for Development

If the executable file indicates that “libfun_so.so” is missing, copy “libfun_so.so” to the root directory’s “/lib” or “/usr/lib” directory because the system executes the program, defaulting to pull dynamic libraries from that path.

3.2 Generate Static Library

Write a test routine, the generated library file is the library file called in section 3.1 (libfun_a.a). The file storage directory structure is as follows:

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

The Makefile file is the “Makefile for Compiling Static Libraries” template from section 2.2.

Compile to generate a static library:

Universal Makefile Templates for Development

3.3 Generate Dynamic Library

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

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

Compile to generate a dynamic library:

Universal Makefile Templates for Development

Copyright Notice:

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

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

Finally

The author has collected some embedded learning materials,
Reply "1024" in the public account to get the download link~
Recommended Articles Click on the blue text to jump
☞ Collection | Comprehensive Programming in Linux Applications
☞ Collection | Learn Some Networking Knowledge
☞ Collection | Handwritten C Language
☞ Collection | Handwritten C++ Language
☞ Collection | Experience Sharing
☞ Collection | From Microcontrollers to Linux
☞ Collection | Power Control Technology
☞ Collection | Essential Mathematics Knowledge for Embedded Systems
☞ MCU Advanced Collection
☞ Embedded C Language Advanced Collection
☞ Experience Sharing

Leave a Comment