项目管理级别的自动万能通用makefile模板:t-makefile (freetoo)

【OpenCV】使用cmake生成MakeFile时下载文件 在编译OpenCV以及其附加模块时,有时会需要一些第三方的库,如果本地没有,会自动下载,下载地址一般为GitHub,结果当然就是卡死在那里,根本无法下载,下面教大家如何解决这种问题。 问题重现比如我在使用cmake配置的过程中出现以下情况:Call Stack (most recent call first): /home/ryan/build/opencv_contrib-master/mod 阅读详情

 

项目管理级别的自动万能通用makefile模板:t-makefile (freetoo)

 

t-makefile源码及示例项目下载链接(会不定期更新):

https://github.com/freetoo/t-makefile

 


一、t-makefile解决的痛点和难点

往往在一个项目工程中,目录名改变了、子目录变更位置了都需要去修改makefile,目录繁多的时候修改makefile也是一件耗时的工作。有没有一个自动的makefile呢?

对于makefile所在的当前目录及其子目录来说,自动makefile的功能实现是非常容易的事情,但难点是:

1、如何自动识别上层目录中(项目目录范围内)的公共目录

2、如何排除一些无关的目录,比如.git目录、test目录、tmp目录、doc目录等。

t-makefile正是解决了以上痛点和难点,从而达到了自动化的目的。t-makefile是一个高度自动化的项目管理级别的makefile源码,能够使您的linux c/c++项目的协同开发工作更加的便捷和高效。

 


二、t-makefile功能:

1、自动搜索源码、头文件、库文件目录并形成有效目录列表和有效文件列表

2、自动识别总makefile功能,可批量执行子目录的makefile

3、自动以目录名为TARGET文件名

4、可动态和静态混合链接成TARGET文件

5、可设置排除目录,避免搜索编译无关源码

6、目录框架灵活设定,框架内可自由移动子makefile仍具有自动功能

7、可避免链接无关符号(函数和变量),避免TARGET体积臃肿

8、支持test目录,可自动包含test工程引用到的模块源码,并能排除其它test目录

9、支持交叉编译,并自动搜索交叉编译环境下的项目库文件(.a/.so)

10、设置简单:仅需设置单个目录的名称即可(不需全路径名)

 


三、t-makefile作用域

t-makefile依赖build.mk文件(主makefle文件)放在项目根目录,若干个子Makefile分布在项目子目录下。

t-makefile的作用域是:makefile的当前目录及子其目录+上层公共目录及其子目录。

注:上层公共目录是指makefile所在的目录向上到项目根目录或build.mk文件所在的目录的每一级目录的一级子目录(由变量COMMON_DIR_NAMES指定名称)。

公共目录示例:

 │─Project─│─Process─│─Module─│─Test─│

    ├── 01-lib
    ├── 02-com
    ├── tcp-client
    │     ├──────── 01-lib
    │     ├──────── 02-inc
    │     ├──────── Module1
    │     ├──────── Module2
    │     │            └────────── test
    │     │                          └──────── Makefile(test)
    │     └──────── Makefile(Process)
    ├── tcp-server
    ├── build.mk
    └── Makefile


说明:对于test目录的Makefile来说,它的公共目录就是: 

project/01-lib
project/02-inc
project/tcp-client/01-lib
project/tcp-client/02-com

 


四、规范约定

本章介绍的几种项目目录结构规范,仅作参考。目录结构之外的其它规范一定要遵守,如“main函数文件规范”和“库文件命名规范”。

1、 main函数文件规范

main函数所在文件名必须是main.c或main.cpp,且必须和makefile同在一个目录。

process-name
   ├──── inc
   ├──── src
   ├──── test
   ├──── main.c(cpp)
   └──── Makefile

2、 库文件命名规范

正常库文件命名规范:前缀(lib)+库名+后缀(.a/.so),如:

libcrc.a

交叉编译库文件命名规范:前缀(lib)+交叉编译关键字(arm-linux-gnueabihf-)+库名+后缀(.a/.so),如:

libarm-linux-gnueabihf-crc.a

交叉编译关键字需要设置makefile的变量CROSS_COMPILE_LIB_KEY才能自动识别,如:

CROSS_COMPILE_LIB_KEY ?= arm-linux-gnueabihf-

3、 模块目录规范(含库模块)

    模块目录规范1 (文件和实现文件分开目录):

module(lib)-name
   ├──── lib
   ├──── inc
   ├──── src
   └──── test

    模块目录规范2 (头文件和实现文件同在一个目录):

module(lib)-name
   ├──── lib
   ├──── test
   ├──── *.h(hpp)
   └──── *.c(cpp)

4、 test目录规范    

module(lib)-name
   ├──── *.h(hpp)
   ├──── *.c(cpp)
   └──── test
           ├──── main.c(cpp)
           └──── Makefile

5、 库目录规范

   有.a/.so库文件的库目录,库文件所在目录及其子目录下的源码文件不会重复编译,该库文件的头文件应该和库文件同在一个目录下或者库文件所在目录的inc子目录下。

   库目录规范1 (无源码的.a/.so文件):

lib-name
   ├──── *.h(hpp)
   ├──── *.a(so)
   └──── test

    库目录规范2  (有源码无.a/.so文件):

lib-name
   ├──── test
   ├──── *.h(hpp)
   └──── *.c(cpp)

   库目录规范3  (有源码有.a/.so文件,且*.c(cpp)文件不会重复编译):

lib-name
   ├──── test
   ├──── *.h(hpp)
   ├──── *.c(cpp)
   ├──── *.a(so)
   └──── Makefile

6、 进程目录规范

    进程目录规范1 (文件和实现文件分开目录):

process-name
   ├──── lib
   ├──── common
   ├──── inc
   ├──── src
   │      ├──── module-name1
   │      └──── module-name2
   ├──── main.c(cpp)
   └──── Makefile

    进程目录规范2 (头文件和实现文件同在一个目录):

process-name
   ├──── 01-lib
   ├──── 02-common
   ├──── module-name1
   ├──── module-name2
   ├──── main.c(cpp)
   └──── Makefile

 


五、项目部署

1、确定目录规范:

你可以根据第四章的目录规范样板统一目录结构,也可以自行定义规范。以下为个人推荐的目录结构规范(个人观点):

● 全局共享的库(公共)目录应该放在项目根目录(lib/common)下,比如进程间公用的库和进程间的通讯协议等。

● 进程专用的库(公共)目录应该放在进程根目录(lib/common)下,比如进程下各个模块公用的库和模块间的接口协议等。

● 模块专用的库目录应该放在模块根目录(lib)下,此部分的库仅为该模块专用的。

● 头文件(*.h/*.hpp)和实现文件(*.c/*.cpp)尽可能的同在一个目录。

上述库(公共)目录规范能够保证各个进程和模块的独立性(尤其在多人协同开发时更显得重要),并且可以避免繁琐的目录跳转以提高工作效率也便于维护和阅读源码,特别是在使用gitlab的子模块功能的时候目录的独立性显得更为重要。

以下是一个简洁的项目目录规范示例:

project-name
    ├── 01-lib
    │     ├── crc
    │     └── md5
    ├── 02-common
    │     └── proto
    ├── process-name1
    ├── process-name2
    │      ├── 01-lib
    │      ├── 02-common
    │      ├── module-name1
    │      ├── module-name2
    │      │      ├── lib
    │      │      └── test
    │      │            └── makefile
    │      │
    │      └── makefile
    │
    ├── makefile
    └── build.mk 

2、下载t-makefile

下载t-makefile解压后将t-makefile目录下的build.mk和makefile文件复制到你的项目根目录下。

3、项目初期设置(设置build.mk文件,您也可也使用默认值这样就基本不需要修改设置)

    a、设置测试目录名(用于识别测试项目和排除其它测试目录的代码):

TEST_DIR_NAME ?= test

    b、设置临时目录名(用于存放编译时的*.o*.d等临时文件):            

TMP_DIR ?= tmp

    c、设置公共目录名(用于makefile向上层目录搜索公共库和公共接口代码等):

COMMON_DIR_NAMES ?= lib inc include com comment 

    d、设置要排除目录名(用于排除无关目录):             

EXCLUDE_DIR_NAMES ?= .git tmp temp doc docs bak

   e、设置相关编译选项

       根据实际需求设置各项编译选项。

4、派发makefile文件

将项目根目录下的makefile派发到各个进程目录或模块的test目录作为子makefile来用,此后可以根据实际需求简单修改子makefile即可。

注:其他功能设置请参阅第六章。

 


六、t-makefile功能设置:

1、总makefile功能

makefile所在目录无main.c、main.cpp文件和输出目标文件不是.a及.so文件时,自动默认为总makefile功能,makefile会执行子目录下的所有makefile文件(如果是“make”命令的则排除test目录下的makefile,是“make clean”的则执行所有的)。

或者执行make命令是加ALL=y参数即可强行执行子目录下的所有makefile。

2、自动以目录名为TARGET文件名

如果不手动设置变量TARGET,则默认以makefile的父目录名为输出文件名。如果是test目录,则以上层目录名加上“_test”。

3、动态和静态混合链接成TARGET文件

由变量DYMAMIC_LDFLAGS和STATIC_LDFLAGS的组合设置来决定是否是混合链接、还是纯动态链接和纯静态链接。

4、排除makefile所在目录下的功能模块目录

多人开发的时候,部分模块尚未完工的,可以设置该模块的目录名(目录要具有唯一性)将其排除在作用域范围之外,makefile还会自动创建该模块的宏定义(EXC_+大写模块名),你可以用此宏定义来做代码中的条件编译。

变量设置:EXCLUDE_DIR_NAMES += ModuleName

宏定义名:EXC_MODULENAME

5、模块独立调试时引用其它功能模块

某个模块在test目录独立调试时,需要引用其它已经完工模块的,仅需设置该模块的目录名称即可(目录要具有唯一性),makefile还会自动创建该模块的宏定义(INC_+大写模块名),你可以用此宏定义来做代码中的条件编译。

变量设置:INCLUDE_MODULE_NAMES += ModuleName

宏定义名:INC_MODULENAME

注:可参考示例工程multi-process1/client/Module2/test目录下的makefile。

6、交叉编译和识别交叉编译的库文件

用于交叉编译设置的变量(设置前请将交叉编译链可执行程序的路径设置到系统的环境变量PATH中,或者使用全路径名设置变量CROSS_COMPILE):

CROSS_COMPILE ?= arm-linux-gnueabihf-

# or

CROSS_COMPILE ?= /xxx/arm-linux-gnueabihf-

用于选择交叉编译使用的库文件的变量:

CROSS_COMPILE_LIB_KEY ?= arm-linux-gnueabihf-

注:makefile会根据CROSS_COMPILE_LIB_KEY的设置自动识别合适的库文件,关于库文件的命名规范请参阅3.8章节。

 


七、用法说明(make命令参数)

     1、make                                                    # 正常编译 
     2、make clean                                        # 清除临时文件及TARGET文件 
     3、make INFO=1                                     # 编译时打印详细信息 
     4、make INFO=2                                     # 静默编译无任何信息输出
     5、make CROSS_COMPILE=...           # 交叉编译设置,或者修改makefile
     6、make [clean] ALL=y                          # 执行本目录和子目录的makefile

 


八、示例项目说明

1、示例目录说明

示例项目中有三种目录结构的项目工程,它们的makefile文件高度一致,也就是说t-makefile的自动功能很完善。
A、multi-process1:简约目录结构的多进程项目工程(目录层次浅操作维护简单)
B、multi-progress2:标准目录结构的多进程项目工程(目录层次深操作维护繁琐)
C、single-progress:单一进程的项目工程

2、示例目录结构

示例目录结构是一个大(总)项目、子项目、多进程、多个模块的目录结构。子项目(multi-process1、multi-progress2、single-progress)可设置变量“PROJECT_ROOT_DIR_NAME”即可使用到总项目目录下的公共目录01-lib、02-com(即tmf-demo-project/01-lib、tmf-demo-project/02-com),参考multi-process1项目的build.mk文件设置:

PROJECT_ROOT_DIR_NAME ?= tmf-demo-project

示例目录结构如下:

| big-project | sub-project | process | module |

tmf-demo-project
├── 01-lib
├── 02-com
├── multi-process1
│   ├── 01-lib
│   ├── 02-com
│   ├── server
│   ├── client
│   │   ├── 01-lib
│   │   ├── 02-com
│   │   ├── Makefile
│   │   ├── Module1
│   │   │   ├── lib
│   │   │   └── test
│   │   └── Module2
│   │       ├── lib
│   │       └── test
│   ├── build.mk
│   └── Makefile
│
├── multi-process2
│   ├── inc
│   ├── lib
│   ├── src
│   │   ├── server
│   │   └── client
│   │       ├── inc
│   │       ├── lib
│   │       └── src
│   │           ├── Module1
│   │           │   ├── src
│   │           │   └── test
│   │           └── Module2
│   │               ├── src
│   │               └── test
│   ├── build.mk
│   └── Makefile
│
└── single-process
    ├── 01-lib
    ├── 02-com
    ├── 03-inc
    ├── Module1
    ├── Module2
    │
    └── Makefile

 


九、主makefile源码(最新版请从题头的链接下载)

############################################################
# Copyleft ©2018 freetoo(yigui-lu)
# name: t-makefile automatic makefile for ubuntu
# qq/wx: 48092788    e-mail: gcode@qq.com
# cn-help: https://blog.youkuaiyun.com/guestcode/article/details/81229127
# download: https://github.com/freetoo/t-makefile
# create: 2018-7-7
############################################################

# t-makefile功能说明:
#     1、自动搜索源码、头文件、库文件目录并形成有效目录列表和文件列表
#     2、自动识别总makefile功能,可批量执行子目录的makefile
#     3、自动以目录名为TTARGET文件名
#     4、可动态和静态混合链接成TARGET文件
#     5、可设置排除目录,避免搜索编译无关源码
#     6、目录框架灵活设定,框架内可自由移动子makefile仍具有自动功能
#     7、可避免链接无关符号(函数和变量),避免TARGET体积臃肿

# 使用方法(usage): 
#     1、make                             # 正常编译 
#     2、make clean                       # 清除临时文件及TARGET文件 
#     3、make INFO=1                      # 编译时打印详细信息 
#     4、make INFO=2                      # 静默编译 
#     5、make CROSS_COMPILE=...           # 交叉编译设置
#     6、make [clean] ALL=y               # 执行本目录和子目录的makefile

# 自动makefile作用域(示例):
# Automatic makefile scope(demo):
#
# │───Project───│───Process───│───Module───│───Test───│
#
#	├── 01-lib
#	├── 02-com
#	├── tcp-client
#	│     ├──────── 01-lib
#	│     ├──────── 02-inc
#	│     ├──────── Module1
#	│     ├──────── Module2
#	│     │            └────────── test
#	│     │                          └──────── Makefile(test)
#	│     └──────── Makefile(Process)
#	├── tcp-server
#	├── build.mk
#	└── Makefile
#
# Makefile Scope:current directory(subdirectory) + upper common directory(subdirectory)
# The setting of the upper common directory reference variable COMMON_DIR_NAMES
#
# makefile的作用域是:当前目录及子其目录+上层公共目录及其子目录,
# 公共目录的设置参考变量COMMON_DIR_NAMES的设置。

# 名词解释:
#   上层、向上:是指由makefile所在目录向系统根目录方向到build.mk文件
#             所在的目录位置的若干层目录。

############################################################
# 常用设置项
############################################################
# 输出目标文件名,不设置则默认使用makefile所在的目录名
# 注意:makefile要和main.c/main.cpp文件同级目录
#TARGET ?=
TARGET ?=

# 要包含的上层模块目录名列表(在makefile作用域内)
# 但要确保名称的唯一性,且为上层目录的一级目录名。
# 对于要包含的模块,makefile会为其增加宏定义用于条件编译:INC_MODULENAME
#INCLUDE_MODULE_NAMES += ModuleName
INCLUDE_MODULE_NAMES +=

# 要排除的模块目录名列表(在makefile作用域内)
# 对于要排除的模块,makefile会为其增加宏定义用于条件编译:EXC_MODULENAME
#EXCLUDE_DIR_NAMES += ModuleName
EXCLUDE_MODULE_NAMES +=

############################################################
# 编译设置部分(Compile setup part)
############################################################
# 设置调试编译选项(Setting the debug compilation options)
#DEBUG ?= y
DEBUG ?= y

# 宏定义列表(macro definition),用于代码条件编译,不需要前面加-D,makefile会自动补上-D
#DEFS ?= DEBUG WIN32 ...
DEFS +=

# C代码编译标志(C code compile flag)
#CC_FLAGS  ?= -Wall -Wfatal-errors -MMD
CC_FLAGS  ?= -Wall -Wfatal-errors -MMD

# C++代码编译标志(C++ code compile flag),注:最终CXX_FLAGS += $(CC_FLAGS)()
#CXX_FLAGS ?= -std=c++11
CXX_FLAGS ?= -std=c++11

# 编译静态库文件设置标志(Compiling a static library file setting flag)
#AR_FLAGS ?= -cr
AR_FLAGS ?= -cr

# 链接标志,默认纯动态链接模式(Link flag, default pure dynamic link mode)
# static  mode: DYMAMIC_LDFLAG ?=        STATIC_LDFLAGS ?=
#               DYMAMIC_LDFLAG ?= ...    STATIC_LDFLAGS ?=
# dynamic mode: DYMAMIC_LDFLAG ?=        STATIC_LDFLAGS ?= ... 
# bland   mode: DYMAMIC_LDFLAG ?= ...    STATIC_LDFLAGS ?= ... 
#
# 动态链接标志(dynamic link flag)
#DYMAMIC_LDFLAGS += -lrt -lpthread
DYMAMIC_LDFLAGS ?= -lrt -lpthread
# 静态链接标志(static link flag)
#STATIC_LDFLAGS += -lrt -ldl -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
STATIC_LDFLAGS ?=

# 交叉编译设置,关联设置:CROSS_COMPILE_LIB_KEY
#CROSS_COMPILE ?= arm-linux-gnueabihf-
#CROSS_COMPILE ?= /usr/bin/arm-linux-gnueabihf-
CROSS_COMPILE ?=

# 交叉编译链库文件的关键字变量设置,用于识别交叉编译链的库文件
# 例如项目中有同样功能的库文件libcrc.a和libarm-linux-gnueabihf-crc.a,
# makefile会根据CROSS_COMPILE_LIB_KEY的设置来选择相应的库文件。
#CROSS_COMPILE_LIB_KEY ?= arm-linux-gnueabihf-
CROSS_COMPILE_LIB_KEY ?= arm-linux-gnueabihf-

############################################################
# 项目规划初期设置
############################################################
# 项目根目录名,不设置则自动以build.mk文件目录为准,如果也没有build.mk文件
# 则自动以makefile所在文件为准。
# PROJECT_ROOT_DIR_NAME ?= tmf-demo
PROJECT_ROOT_DIR_NAME ?=

# 测试目录的目录名称,makefile会排除在搜索范围之外(makefile所在目录例外)
#TEST_DIR_NAME ?= test
TEST_DIR_NAME ?= test

# 临时目录的目录名称,makefile会排除在搜索范围之外
# 编译时临时文件(.o/.d等文件)所在的目录,如果不设置则默认为tmp
#TMP_DIR ?= tmp
TMP_DIR ?= tmp

# 要包含的上层公共目录名列表,包含库目录、头文件目录等的目录名
#COMMON_DIR_NAMES += lib inc include com common \
#					01-lib 01-inc 01-include 01-com 01-common \
#					02-lib 02-inc 02-include 02-com 02-common \
#					03-lib 03-inc 03-include 03-com 03-common
COMMON_DIR_NAMES ?= lib inc include com common \
					01-lib 01-inc 01-include 01-com 01-common \
					02-lib 02-inc 02-include 02-com 02-common \
					03-lib 03-inc 03-include 03-com 03-common

# 头文件目录名列表,INC_DIR_NAMES是COMMON_DIR_NAMES的子集,
# 一旦设置了本变量,makefile只将其及其子目录加入编译参数-I中。
# 如果不设置,makefile会自动搜含有头文件的目录加入编译参数-I中。
#INC_DIR_NAMES ?= inc include 01-inc 01-include 02-inc 02-include 03-inc 03-include
INC_DIR_NAMES ?=

# 要排除的目录名列表,比如文档目录、备份目录等
#EXCLUDE_DIR_NAMES += .git tmp temp doc docs bak
EXCLUDE_DIR_NAMES ?= .git tmp temp doc docs bak

############################################################
# TARGET后置处理及杂项设置
############################################################
# makefile所在目录的全路径名称
CUR_DIR ?= $(shell pwd)
# makefile所在的目录名称
CUR_DIR_NAME := $(notdir $(CUR_DIR))

# 如果是test目录,SRC_DIR则向上跳一层
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))
  SRC_DIR := $(shell dirname $(CUR_DIR))
else
  SRC_DIR := $(CUR_DIR)
endif

# 如果没有手动设置TARGET,则设置为makefile所在的目录名称
ifeq ($(TARGET),)
  TARGET := $(notdir $(SRC_DIR))
  ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))
    TARGET := $(TARGET)_$(TEST_DIR_NAME)
  endif
  ifneq ($(CROSS_COMPILE),)
    ifneq ($(CROSS_COMPILE_LIB_KEY),)
      TARGET := $(TARGET:lib%=lib$(CROSS_COMPILE_LIB_KEY)%)
    endif
  endif
endif

# 是编译exec文件还是库文件
IS_LIB_TARGET := $(suffix $(TARGET))
# 目标文件是库文件?
ifneq ($(IS_LIB_TARGET),)
  IS_LIB_TARGET := $(shell if [ $(IS_LIB_TARGET) = .a ] || [ $(IS_LIB_TARGET) = .so ]; then echo y; fi;)
endif

ifeq ($(IS_LIB_TARGET),y)
  # 补充lib前缀
  TARGET := $(if $(findstring lib,$(TARGET)),$(TARGET),lib$(TARGET))
  TMP_TARGET := $(basename $(TARGET))
else
  TMP_TARGET := $(TARGET)
endif

# 查找main文件
MAIN_FILE := $(shell find $(CUR_DIR) -maxdepth 1 -type f -iname 'main.c' -o -type f -iname 'main.cpp')
# 无main文件也不是编译库文件,则认为是总makefile功能
ifeq ($(MAIN_FILE)$(IS_LIB_TARGET),)
  TARGET :=
  MAKE_SUB := y
endif
# 入口参数ALL表示手动设置总makefile功能
ifeq ($(ALL),y)
  MAKE_SUB := y
endif

# 编译信息显示设置,1:为全部显示,2:仅显示步骤项,其它:静默无显示
ifeq ($(INFO),1)
  BUILD_INFO=
  STEP_INFO=@echo
else ifeq ($(INFO),2)
  BUILD_INFO=@
  STEP_INFO=@true
else
  BUILD_INFO=@
  STEP_INFO=@echo
endif

# 文件目录操作变量
RM      := rm -rf
MKDIR   := mkdir -p
MAKE    := make

############################################################
# 编译定义项及编译设置项的后置处理(非常用项,修改需谨慎)
############################################################

# c/c++编译器名称,默认为gcc,有cpp文件则被自动改为g++
CC  := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
AR  := $(CROSS_COMPILE)ar
# 默认链接器是gcc,如果有cpp文件makefile会自动设置为g++
ifeq ($(suffix $(MAIN_FILE)),.cpp)
  LD := $(CXX)
else
  LD := $(CC)
endif

# 宏定义列表
# 转大写,+INC前缀
tmp := $(shell echo $(INCLUDE_MODULE_NAMES) | tr '[a-z]' '[A-Z]')
DEFS := $(DEFS) $(tmp:%=INC_%)
# 转大写,+EXC前缀
tmp := $(shell echo $(EXCLUDE_MODULE_NAMES) | tr '[a-z]' '[A-Z]')
DEFS := $(DEFS) $(tmp:%=EXC_%)
DEFS := $(DEFS:%=-D%)

# C代码编译设置标志
CC_FLAGS += $(DEFS)
ifeq ($(DEBUG), y)
  CC_FLAGS += -ggdb -rdynamic -g
else
  CC_FLAGS += -O2 -s
endif
# 不使用到的符号不链接到目标文件中
CC_FLAGS += -ffunction-sections -fdata-sections

# 链接标志和链接库设置(除TOP_MODULE_DIRS目录下的*.a和*.so文件之外的链接库设置)
# STATIC_LIB_FILES和DYNAMIC_LIB_FILES变量是makefile作用域里面的.a和.so文件列表,请一定保留
DYMAMIC_LDFLAGS := $(strip $(DYMAMIC_LDFLAGS))
STATIC_LDFLAGS := $(strip $(STATIC_LDFLAGS))
ifeq ($(DYMAMIC_LDFLAGS)$(STATIC_LDFLAGS),$(DYMAMIC_LDFLAGS))
  # 纯动态链接模式
  #LDFLAGS ?= -Wl,--as-needed -lrt -lpthread $(DYNAMIC_LIB_FILES) $(STATIC_LIB_FILES)
  LDFLAGS ?= $(DYNAMIC_LIB_FILES) $(STATIC_LIB_FILES) $(DYMAMIC_LDFLAGS)
else ifeq ($(DYMAMIC_LDFLAGS)$(STATIC_LDFLAGS),$(STATIC_LDFLAGS))
  # 纯静态链接模式
  #LDFLAGS ?= -static -lrt -Wl,--whole-archive -lpthread -Wl,--no-whole-archive $(STATIC_LIB_FILES)
  LDFLAGS ?= -static $(STATIC_LIB_FILES) $(STATIC_LDFLAGS)
else
  # 动态静态混合链接模式
  # 模板:LDFLAGS = -Wl,-Bstatic ... $(STATIC_LIB_FILES) -Wl,--as-needed -Wl,-Bdynamic ... $(DYNAMIC_LIB_FILES)
  #LDFLAGS ?= -Wl,-Bstatic -lpthread $(STATIC_LIB_FILES) -Wl,--as-needed -Wl,-Bdynamic -lrt $(DYNAMIC_LIB_FILES)
  LDFLAGS ?= -Wl,-Bstatic $(STATIC_LIB_FILES) $(STATIC_LDFLAGS) -Wl,-Bdynamic $(DYNAMIC_LIB_FILES) $(STATIC_LDFLAGS)
endif
LDFLAGS += -Wl,--gc-sections

# 编译动态库设置项
ifeq ($(suffix $(TARGET)),.so)
  CC_FLAGS += -fPIC
  LDFLAGS += -shared
endif

# 最终CXX_FLAGS包含CC_FLAGS
CXX_FLAGS += $(CC_FLAGS)

# 检查编译so文件时,是否是错误设置为静态链接标志
CHECK_LDFLAGS := $(if $(findstring static,$(LDFLAGS)),'Error: build file(*.so) not use static flag',)

############################################################
# 文件和路径搜索部分(非常用项,修改需谨慎)
############################################################
INCLUDE_MODULE_NAMES := $(strip $(INCLUDE_MODULE_NAMES))
EXCLUDE_MODULE_NAMES := $(strip $(EXCLUDE_MODULE_NAMES))
COMMON_DIR_NAMES := $(strip $(COMMON_DIR_NAMES))
EXCLUDE_DIR_NAMES := $(strip $(EXCLUDE_DIR_NAMES))
SPACE :=
SPACE:= $(SPACE) $(SPACE)

# 如果是总makefile
ifneq ($(MAKE_SUB),)
  # 不包含test目录名的排除目录名的列表
  tmp := $(subst $(SPACE),\\\|,$(strip $(EXCLUDE_DIR_NAMES)))
  # 执行make clean命令的makefile所在目录列表,包含test目录
  MF_CLEAN_DIRS := $(dir $(shell find . -type f -iname Makefile | grep -v $(tmp)))
  MF_CLEAN_DIRS := $(foreach dir,$(MF_CLEAN_DIRS),$(shell if [ ! $(dir) = ./ ]; then echo $(dir); fi;))
endif

# 要排除的目录名列表
EXCLUDE_DIR_NAMES += $(EXCLUDE_MODULE_NAMES) $(TEST_DIR_NAME)
EXCLUDE_DIR_NAMES := $(subst $(SPACE),\\\|,$(strip $(EXCLUDE_DIR_NAMES)))
# 如果是总makefile
ifneq ($(MAKE_SUB),)
  # 执行make命令的makefile所在目录列表,不包含test目录
  MF_MAKE_DIRS := $(dir $(shell find . -type f -iname Makefile | grep -v $(EXCLUDE_DIR_NAMES)))
  MF_MAKE_DIRS := $(foreach dir,$(MF_MAKE_DIRS),$(shell if [ ! $(dir) = ./ ]; then echo $(dir); fi;))
endif

# 如果没设置临时,默认等于tmp
ifeq ($(TMP_DIR),)
  TMP_DIR := tmp
endif

# build.mk文件所在目录,如果没有build.mk则等于当前目录
 BUILDMK_DIR ?= $(shell result=$(CUR_DIR); \
							for dir in $(strip $(subst /, ,$(CUR_DIR))); \
							do \
								dirs=$$dirs/$$dir; \
								if [ -f $$dirs/build.mk ]; then \
									result=$$dirs; \
								fi; \
							done; \
							echo $$result; \
					)

# 项目根目录全路径名称
ifneq ($(PROJECT_ROOT_DIR_NAME),)
  PROJECT_ROOT_DIR := $(shell result=$(BUILDMK_DIR); \
							for dir in $(strip $(subst /, ,$(CUR_DIR))); \
							do \
								dirs=$$dirs/$$dir; \
								if [ $$dir = $(PROJECT_ROOT_DIR_NAME) ]; then \
									result=$$dirs; \
									break; \
								fi; \
							done; \
							echo $$result; \
					)
else
  PROJECT_ROOT_DIR := $(BUILDMK_DIR)
endif

# 向上搜索COMMON_DIR_NAMES指定名称的公共目录,库文件编译除外
ifeq ($(IS_LIB_TARGET),)
ifneq ($(PROJECT_ROOT_DIR),)
  COMMON_DIR_NAMES += $(INCLUDE_MODULE_NAMES)
  tmp := $(strip $(subst /, ,$(subst $(PROJECT_ROOT_DIR),,$(SRC_DIR))))
  tmp := $(shell Dirs=$(PROJECT_ROOT_DIR); \
  			echo $$Dirs; \
			for dir in $(tmp); \
			do \
				Dirs=$$Dirs/$$dir; \
				echo $$Dirs; \
			done; \
		)
  COMMON_DIRS := $(shell \
					for dir in $(tmp); \
					do \
						for name in $(COMMON_DIR_NAMES); \
						do \
							if [ -d $$dir/$$name ];then \
								echo $$dir/$$name; \
							fi; \
						done; \
					done; \
				)
endif
endif

# 所有文件列表
SRC_DIRS += $(SRC_DIR)
tmp := $(COMMON_DIRS) $(filter-out $(COMMON_DIRS:%=%%),$(SRC_DIRS))
ALL_FILES := $(shell find $(tmp)  \
						-type f -name '*.h' -o -type f -name '*.hpp' \
						-o -type f -name '*.c' -o -type f -name '*.cpp' \
						-o -type f -name '*.a' -o -type f -name '*.so' \
						| grep -vw 'main.c\|main.cpp' \
						| grep -vw $(EXCLUDE_DIR_NAMES))
EXCLUDE_DIR_NAMES :=
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))
  ALL_FILES += $(shell find $(CUR_DIR) -type f -name '*.h' -o -type f -name '*.hpp' \
						-o -type f -name '*.c' -o -type f -name '*.cpp' \
						-o -type f -name '*.a' -o -type f -name '*.so' \
						| grep -vw 'main.c\|main.cpp\|'$(TMP_DIR))
endif

# 所有库文件
LIB_FILES := $(filter %.a %.so,$(ALL_FILES))
ifneq ($(LIB_FILES),)
  # 库文件列表
  ifneq ($(IS_LIB_TARGET),)
  	LIB_FILES := $(filter $(CUR_DIR)%,$(LIB_FILES))
  	tmp := $(TMP_TARGET:lib%=%)
    LIB_FILES := $(filter-out $(CUR_DIR)/%$(tmp).a $(CUR_DIR)/%$(tmp).so,$(LIB_FILES))
  endif  

  # 所有库文件目录
  LIB_DIRS += $(sort $(dir $(LIB_FILES)))
  LIB_DIRS := $(strip $(LIB_DIRS))
  LIB_OUT_DIRS := $(LIB_DIRS:%=%%)
  LOAD_LIB_PATH := $(sort $(dir $(filter %.so,$(LIB_FILES))))
  
  # 库文件列表
  LIB_FILES := $(notdir $(LIB_FILES))
  # 如果是交叉编译,则使用交叉编译链的库文件并排除同名的非交叉编译链的库文件
  ifneq ($(CROSS_COMPILE),)
    ifneq ($(CROSS_COMPILE_LIB_KEY),)
      tmp := $(filter lib$(CROSS_COMPILE_LIB_KEY)%,$(LIB_FILES))
      tmp := $(subst $(CROSS_COMPILE_LIB_KEY),,$(tmp))
      LIB_FILES := $(filter-out $(tmp),$(LIB_FILES))
    endif
  else
    # 不是交叉编译链,排除交叉编译链的库文件
    LIB_FILES := $(filter-out lib$(CROSS_COMPILE_LIB_KEY)%,$(LIB_FILES))
  endif
  # 静态库文件列表
  STATIC_LIB_FILES := $(filter %.a,$(LIB_FILES))
  STATIC_LIB_FILES := $(STATIC_LIB_FILES:lib%.a=-l%)
  # 动态库文件列表
  DYNAMIC_LIB_FILES := $(filter %.so,$(LIB_FILES))
  LIB_FILES :=
  DYNAMIC_LIB_FILES := $(DYNAMIC_LIB_FILES:lib%.so=-l%)
endif # ifneq ($(LIB_FILES),)

# 源文件目录及obj文件列表
tmp := $(filter %.c %.cpp,$(ALL_FILES))
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))
OBJ_FILES := $(filter $(CUR_DIR)%,$(tmp))
tmp := $(filter-out $(CUR_DIR)%,$(tmp))
endif
ifneq ($(LIB_DIRS),)
  # 过滤译库文件(.a/.so)的源码文件
  tmp := $(filter-out $(LIB_OUT_DIRS),$(tmp))
endif
# .o文件列表
TMP_DIR := $(TMP_DIR)/
OBJ_FILES += $(tmp)
OBJ_FILES := $(OBJ_FILES:%.c=$(TMP_DIR)%.o)
OBJ_FILES := $(OBJ_FILES:%.cpp=$(TMP_DIR)%.o)
MAIN_FILE := $(MAIN_FILE:%.c=$(TMP_DIR)%.o)
MAIN_FILE := $(MAIN_FILE:%.cpp=$(TMP_DIR)%.o)
ifeq ($(OBJ_FILES),)
  TMP_TARGET := $(TARGET)
endif


# 头文件所在目录
tmp := $(sort $(dir $(filter %.h %.hpp,$(ALL_FILES))))
ifeq ($(CUR_DIR_NAME),$(TEST_DIR_NAME))
INC_DIRS += $(filter $(CUR_DIR)%,$(tmp))
tmp := $(filter-out $(CUR_DIR)%,$(tmp))
endif
# 如果指定头文件目录名,则过滤掉其它的目录
ifneq ($(INC_DIR_NAMES),)
  tmp := $(foreach item,$(tmp),\
			$(shell \
				isfind=n; \
				for name1 in $(subst /, ,$(item)); \
				do \
					for name2 in $(INC_DIR_NAMES); \
					do \
						if [ $$name1 = $$name2 ]; then \
							isfind=y; \
							break; \
						fi; \
					done; \
					if [ $$isfind = y ]; then \
						break; \
					fi; \
				done; \
				if [ $$isfind = y ]; then \
					echo $(item); \
				fi; \
			) \
		)
else
# 头文件默认和库文件一起放或者放inc目录下
  ifneq ($(LIB_DIRS),)
    tmp2 := $(LIB_DIRS:%=%inc/)
    tmp2 := $(tmp2:%=%%) $(LIB_OUT_DIRS)
    tmp2 := $(filter $(tmp2),$(tmp))
# 过滤译库文件(.a/.so)的其它头文件的目录
    tmp2 += $(filter-out $(LIB_OUT_DIRS),$(tmp))
    tmp := $(sort $(tmp2))
    tmp2 :=
  endif
endif
ALL_FILES :=
INC_DIRS := $(strip $(INC_DIRS)) $(tmp)
tmp :=
INC_DIRS := $(INC_DIRS:%=-I%)

# 所有库目录
LIB_DIRS := $(LIB_DIRS:%=-L%)

# *.c/*/cpp文件搜索的目录,用于编译设置
#VPATH := $(SRC_DIRS)

# 临时库文件,将所有.o文件合并为一个临时.a文件,再和main.o文件链接,
# 避免链接进无用符号造成TARGET文件体积臃肿。
ifneq ($(OBJ_FILES),)
  TMP_LIB_TARGET := libtmp.a
  TMP_LIB_DIRS := -L$(TMP_DIR) $(TMP_LIB_TARGET:lib%.a=-l%)
  TMP_LIB_TARGET := $(TMP_DIR)$(TMP_LIB_TARGET)
endif

############################################################
# 链接成最终文件
############################################################
all: FIRST_EXEC $(TARGET)

FIRST_EXEC:
ifdef DEB
	@echo '**************************************'
	@echo 'PROJECT_ROOT_DIR:'$(PROJECT_ROOT_DIR)
	@echo '**************************************'
	@echo 'TARGET:'$(TARGET)
	@echo '**************************************'
	@echo 'CUR_DIR:'$(CUR_DIR)
	@echo '**************************************'
	@echo 'SRC_DIR:'$(SRC_DIR)
	@echo '**************************************'
	@echo 'COMMON_DIRS:'$(COMMON_DIRS)
	@echo '**************************************'
	@echo 'LIB_DIRS:'$(LIB_DIRS)
	@echo '**************************************'
	@echo 'STATIC_LIB_FILES:'$(STATIC_LIB_FILES)
	@echo '**************************************'
	@echo 'DYNAMIC_LIB_FILES:'$(DYNAMIC_LIB_FILES)
	@echo '**************************************'
	@echo 'INC_DIRS:'$(INC_DIRS)
	@echo '**************************************'
	@echo 'OBJ_FILES:'$(OBJ_FILES)
	@echo '**************************************'
endif
#*********************************************
# 总makefile模式,编译子目录下的所有makefile
ifneq ($(MF_MAKE_DIRS),)
	$(STEP_INFO) '[step] submakefile is making...'
	@for dir in $(MF_MAKE_DIRS); do $(MAKE) -C $$dir; done;
	$(STEP_INFO) '[step] submakefile make done'
endif

#*********************************************
# 生成exec程序
$(TMP_TARGET): $(TMP_LIB_TARGET) $(MAIN_FILE)
ifeq ($(INFO),1)
	@echo '**************************************'
endif
	$(STEP_INFO) '[step] Building exec file: '$@
	$(BUILD_INFO)$(LD) $(MAIN_FILE) $(LIB_DIRS) $(TMP_LIB_DIRS) $(LDFLAGS) -o $@
ifneq ($(LOAD_LIB_PATH),)
# 如果调用到.so文件,请执行以下命令设置库文件的搜索路径变量:LD_LIBRARY_PATH
	@echo '**********************************************************'
	@echo
	@echo 'Please execute the following command to load the LIB path, if you use it(.so):'
	@echo 'LD_LIBRARY_PATH=$(LOAD_LIB_PATH) && export LD_LIBRARY_PATH'
	@echo
endif

#*********************************************
# 生成临时静态库文件
$(TMP_LIB_TARGET): $(OBJ_FILES)
ifeq ($(INFO),1)
	@echo '**************************************'
endif
	$(STEP_INFO) '[step] Building temp static lib file: '$@
	$(BUILD_INFO)$(AR) $(AR_FLAGS) -o $@ $^

#*********************************************
# 生成静态库文件
$(TMP_TARGET).a: $(OBJ_FILES)
ifeq ($(INFO),1)
	@echo '**************************************'
endif
	$(STEP_INFO) '[step] Building static lib file: '$@
	$(BUILD_INFO)$(AR) $(AR_FLAGS) -o $@ $^

#*********************************************
# 生成动态库文件
$(TMP_TARGET).so: $(OBJ_FILES)
ifeq ($(INFO),1)
	@echo '**************************************'
endif
	$(STEP_INFO) '[step] Building dynamic lib file: '$@
ifneq ($(CHECK_LDFLAGS),)
	@echo $(CHECK_LDFLAGS)
endif
	$(BUILD_INFO)$(LD) -o $@ $^ $(LIB_DIRS) $(LDFLAGS) $(DYNC_FLAGS)

#*********************************************
# 编译c代码文件
$(TMP_DIR)%.o: %.c
ifeq ($(INFO),1)
	@echo '**************************************'
endif
	$(STEP_INFO) '[step] Compiling c file: '$<
	@$(MKDIR) $(dir $@)
	$(BUILD_INFO)$(CC) $(CC_FLAGS) -c $< -o $@ $(INC_DIRS)

#*********************************************
# 编译c++代码文件
$(TMP_DIR)%.o: %.cpp
ifeq ($(INFO),1)
	@echo '**************************************'
endif
	$(STEP_INFO) '[step] Compiling cpp file: '$<
	@$(MKDIR) $(dir $@)
	$(BUILD_INFO)$(CXX) $(CXX_FLAGS) -c $< -o $@ $(INC_DIRS)

#*********************************************
# 头文件关联
-include $(OBJ_FILES:.o=.d)

############################################################
# 清理临时文件
############################################################
clean:
ifneq ($(MF_CLEAN_DIRS),)
# 总makefile模式
	$(STEP_INFO) '[step] submakefile cleaning...'
	@for dir in $(MF_CLEAN_DIRS); do $(MAKE) -C $$dir clean; done;
	$(STEP_INFO) '[step] submakefile cleaned'
endif
#*********************************************
# 不删除库目标文件
ifeq ($(IS_LIB_TARGET),)
	@if [ -f $(TARGET) ]; then $(RM) -f $(TARGET); fi;
endif
# 子makefile模式,删除临时目录
	@if [ -d $(TMP_DIR) ]; then $(RM) -r $(TMP_DIR); fi;
	@echo '[step] cleaned'

.PHONY: all clean


 

关键字: make makefile shell find grep wildcard notdir patsubst findstring wordlist suffix foreach gcc g++ c++11 嵌入脚本 静态链接库 动态链接库 静态动态混合编译链接 语法 内嵌函数 函数嵌套执行 替换字符串 判断字符串相等 遍历数组  执行shell脚本 循环 逻辑与 逻辑或  查找文件  搜索文件目录 获取目录名 获取文件名

 

转载请注明出处!

 

u-boot Makefile分析与编程 在上述示例中,目标规则定义了一个名为u-boot.bin的目标,它依赖于u-boot.elf。除了上述基本结构外,u-boot Makefile还可以包含其他功能,如条件语句、循环语句、函数定义等,以实现更复杂的编译和构建逻辑。通过编写类似上述示例的Makefile,您可以根据您的需求进行定制和扩展,以满足u-boot项目的编译和构建需求。在上述示例中,我们首先定义了编译器和选项的变量,然后定义了一组源文件和对象文件的变量。在上述示例中,依赖规则指定了一个名为u-boot.elf的目标,它依赖于。 阅读详情

相关推荐

中文make file

中文版本的makefile文档,很详细,是嵌入式编程利器

vscode+makefile开发STM32(二)---下载

vscode+makefile开发STM32

ApexYuan 1863

Makefile自动化编译模板

Makefile自动化编译实战项目,提供了各种情况的Makefile自动化编译的模板,包括1、项目工程没有子目录的情况 2、项目工程包括子目录的情况 3、项目工程每个子目录都有makefile文件 4、需要生成静态库lib的情况 5、多个静态Lib库生产动态so库的makefile模板

【Linux】自动生成makefile(ubuntu)

Linux系统 用automake工具自动生成Makefile的步骤

LINJUN0423的博客 3932

万能makefile,仅需修改文件名和完整路径即可

打开下面链接,直接免费下载资源: https://renmaiwang.cn/s/hzre5 在Linux环境下,Makefile文件提供了一个简单的编辑模板,基本上能够实现通用编辑的功能。要使用它,只需要更改生成程序的名称以及相应的运行路径设置就可以了。 在Linux系统开发环境中,Makefile文件扮演着至关重要的角色。它是一个自动化编译程序的脚本,能够高效地组织编译过程,确保源代码的快速构建和维护。对于开发者而言,一个精妙设计的Makefile模板可以大大简化开发流程,提高工作效率。尤其当面对多个源文件和多种编译选项时,一个结构良好且功能全面的Makefile,可以快速应对各种构建需求。 通用编辑功能的实现,主要依赖于Makefile中定义的规则和变量。开发者通过指定构建规则,定义编译器选项和链接器选项,能够轻松地控制编译过程。此外,Makefile中还能够嵌入特定的编译指令和命令,使编译过程更加自动化和智能化。 使用Makefile时,通常需要指定目标文件(通常为可执行文件)和依赖文件(源代码文件),并确定相应的编译器和链接器路径。一旦这些基础信息被设定,接下来的构建工作几乎可以完全交给Makefile去执行。这不仅节省了重复输入命令的时间,也避免了因人为错误导致的编译问题。 值得一提的是,对于不同的开发环境和项目需求,Makefile可能需要进行一些定制化修改。然而,一个优秀的通用Makefile模板,其设计应当足够灵活,允许开发者在最小化改动的情况下,适应各种不同的需求。正如提供的万能Makefile模板所展现的那样,用户只需要根据实际情况,修改相关的文件名和路径设置,就可以开始使用。模板化的设计减少了用户从头开始编写Makefile的需要,同时也降低了学习和使用Makefile的门槛。 在此基础上,对于源代码的管理也成为提高开发效率的重要因素。一个完

1.3、云计算HCIP融合存储产品及部署

目标:描述Oceanstor V3系列存储产品系统组成及产品定位 描述Oceanstor V3硬件结构及软件架构 掌握存储系统与主机系统之间的连接 一、存储型号 低端型存储:Oceanstor 2200 2600 2800 V3/V5 终端型存储:Oceanstor 5300 5500 5600 5800 6800 V3/V5 高端型存储:Oceanstor 18000 二、Oceanstor V3系列存储系统定位 OceanStor V3系列存储系统是华为根据存储产品应用现状和存储

weixin_43666279的博客 1652

t-makefile:自动万能通用makefile模板(freetoo 码客 卢益贵)

t-makefile:自动万能通用makefile模板(freetoo 码客 卢益贵)   关键字: make makefile shell find grep wildcard notdir patsubst findstring wordlist suffix foreach gcc g++ c++11 嵌入脚本 静态链接库 动态链接库 静态动态混合编译链接 语法 内嵌函数 函数嵌套执行 ...

码客 卢益贵 ygluu 768

别再只用固定线了!聊聊Android车机‘快速倒车’与‘正常倒车’的UI与数据流核心差异(附动态轨迹线实现原理)

本文深度解析Android车机中快速倒车与正常倒车的核心差异,探讨从内核级视频流水线到动态轨迹线的技术实现。快速倒车通过内核直接操作FrameBuffer实现2秒内响应,而正常倒车则支持多传感器数据融合与动态UI元素。文章还分享了动态轨迹线的算法实现与性能优化技巧,帮助开发者打造极致的倒车体验。

weixin_42550597的博客 252

【亲测免费】 Makefile中文手册下载

Makefile中文手册下载 【下载地址】Makefile中文手册下载分享 Makefile中文手册下载 项目地址: https://gitcode.com/Open-source-documentation-tutorial/7...

gitblog_06601的博客 717

Figma入门-自动布局

Figma原型图制作内置组件友好,自动布局类似CSS flex,通过布局网格控制对齐、分布、换行等,前端熟悉的同学易上手,参数设置基本一致。

我码玄黄的博客 2173

安卓App开发 篇三:Android SDK和API

Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法、减少模板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者可将精力集中于真正重要的编码工作。hl=zh-cnhl=zh-cnWorkManager 是 Android Jetpack 的一部分,是用于持久性工作的推荐解决方案,适用于需要通过应用重启和系统重新启动来调度的工作,也是后台处理操作的主要推荐 API。立即执行:必须立即开始且很快完成的任务,可以加急,使用和Worker,通过对调用处理加急工作。

生活在别处 1278

【开发工具】之windows下gnu makefile编写

ifeq ($(strip $(platform)), x86_32) CC := cl.exe LD := link.exe AR := lib.exe RC := rc.exe EXTRA_CFLAGS := -W3 -nologo -DWIN32 EXTRA_CFLAGS += -D_CRT_SECURE_NO_WARNINGS -O2 EXTRA_LDFLAGS := ...

walkingMa的专栏 1482

自动识别象棋棋子的OpenCV应用

在计算机视觉领域,OpenCV是一个广泛应用的开源计算机视觉库,它提供了丰富的图像处理和分析工具。本文将介绍如何使用OpenCV实现自动识别象棋棋子的功能,并提供相应的源代码。通过以上代码,我们可以实现对棋盘图像中棋子的自动识别。需要注意的是,以上代码只是一个简单的示例,实际应用中可能需要根据具体情况进行参数调整和算法优化,以获得更好的识别效果。函数利用预处理后的图像,寻找图像中的轮廓,并根据轮廓的面积筛选出可能的棋子轮廓,最后在原图像中提取棋子区域。在主程序中,我们读取输入图像,并调用。

WzisTypescript的博客 904

【开发环境】Windows 系统中使用 Makefile 构建脚本编译 C 程序 ( 下载并安装 TDM-GCC 编译器 | 配置环境变量 | 编译 Makefile 程序 )

一、下载 TDM-GCC 编译器、 二、安装 TDM-GCC 编译器、 三、配置环境变量、 四、根据 Makefile 脚本编译 C 程序、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 8120

背靠背VSC直流母线电压控制与同步发电机并网发散问题:原理、分析与解决方案

背靠背VSC直流母线电压控制与同步发电机并网发散问题分析 摘要: 本文研究了背靠背VSC系统在整流侧由理想三相电源切换为同步发电机时出现的直流母线电压振荡和发散问题。通过理论分析发现,锁相环同步失稳、等效阻抗失配和直流母线电容参数失配是导致系统失稳的关键因素。当整流侧接入同步发电机后,系统形成正反馈振荡回路,同时等效电感增大导致电流环响应速度降低,直流侧电容容量不足无法吸收发电机功率波动。文章提出了从跟网型控制到构网型VSG控制的完整升级方案,包含详细的MATLAB/Simulink建模和控制算法实现,并通

huanghm88的专栏 120

(一)激光线扫描-三维成像原理

激光线扫描是一种使用激光作为光源,通过特定的扫描设备(如光学镜头、电机驱动的镜头或电子扫描设备)将激光束引导到目标表面,并按照预定的路径进行扫描的技术。这种技术通常用于测量、检测、打印、切割等多种应用中。

FlyWine的博客 3629

Linux下交叉编译工具的安装与Makefile的使用

Ubuntu安装make 1.自动安装 在Linux 命令行下先获得root权限再执行以下命令 apt install make 2.手动安装 方法二:(手动安装) 1、查看make版本,在浏览器搜索:ftp://ftp.gnu.org/gnu/make/ 可进入下载页面 2、进入文件存放路径:cd /home/tool 3、下载安装包:wget http://ftp.gnu.org/gnu/make/make-3.81.tar.gz 4、解压压缩包:tar -zvxf make-3.81.tar.gz

hwf1877655的博客 2517

传感器校准与标定:传感器的灵敏度校准_(11).常见传感器的灵敏度校准方法

线性校准:适用于传感器输出与输入之间存在线性关系的情况。通过收集数据并使用最小二乘法拟合线性方程,可以确定斜率和截距,从而实现校准。非线性校准:适用于传感器输出与输入之间存在非线性关系的情况。通过收集数据并使用非线性拟合方法(如最小二乘法),可以确定多项式或其他非线性方程的参数,从而实现校准。温度补偿校准:适用于传感器在不同温度下输出特性变化的情况。通过收集不同温度下的数据并使用温度补偿方程,可以提高传感器在不同温度下的测量精度。其他校准方法。

2401_87715305的博客 914

【亲测免费】 Makefile 教程(中文版)下载

Makefile 教程(中文版)下载 【下载地址】Makefile教程中文版下载分享 本仓库提供了一个名为 `makefile教程(中文版).pdf` 的资源文件下载。该文件是一份详细的中文版 Makefile 教程,适合初学者和有一定基础的开发者学习使用 ...

gitblog_06686的博客 633

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

一文入门Makefile

这是因为上面的%可以看成是任意的东西(类似于通配符中的*),当我们的目标的依赖不存在的时候,Makefile就会在规则中寻找是否目标的依赖和哪个规则的目标一致,找到就会执行这个规则中的命令。上面例子把目标文件直接赋值给了变量targetFile,我们在规则中可以使用$(targetFile)的方式取出test的这个值去使用,当然了上面只是简单地做个示范,我们还可以拿变量去装一些更复杂的东西,比如说一堆的文件(没错,一个变量能装的可不止一个文件,用空格隔开可以装多个)那么Makefile到底是做什么的呢?

m0_63235356的博客 1628

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Makefile教程(附通用模板)

Makefile教程(附通用模板)

qq_36973838的博客 1508

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

makefile例子文件已经提供下载

我把前面讲解过的那个makefile文件发布到优快云的资源里面了,感兴趣的同志可以去下载。地址是: http://download.youkuaiyun.com/source/397617

schumyxp的专栏 930

【免费下载】 Makefile经典教程下载

Makefile经典教程下载 【下载地址】Makefile经典教程下载分享 Makefile经典教程下载本仓库提供了一个名为“跟我一起学Makefile.pdf”的资源文件下载 项目地址: https://gitcode.com/...

gitblog_06653的博客 511

[STM32] 教你在vscode下用stm32+makefile+gcc实现一键编译仿真下载

生命在于运动,技术在于折腾,你是否厌倦了在keil、iar下孜孜不倦的写代码、debug,是否玩累了在外部编辑器下写代码,然后在转到ide下进行仿真、下载等操作呢?

ic2121的博客 3647

Makefile教程

安装完成后,查看makefile版本,看是否安装成功make -v。

weixin_52467549的博客 1978
上一篇: t-makefile:自动万能通用makefile模板(freetoo 码客 卢益贵)
下一篇: 一键部署高可用etcd集群(TLS,ubuntu)(freetoo、码客、卢益贵)
ygluu
博客等级 码龄17年 300粉丝 62原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值