当前位置:   article > 正文

makefile管理编译工程 自动生成.h头文件依赖_makefile文件依赖库可以快速找到吗

makefile文件依赖库可以快速找到吗

makefile管理编译工程 自动生成.h头文件依赖

工程目录结构
在这里插入图片描述
每一个功能模块建立一个文件夹,然后该文件夹下建立includelibsrc文件夹。include存放对外接口,lib存放编译好的静态库,src存放源码.c和.h文件。
每个功能模块有单独的makefile进行编译管理。
顶层路径下建立一个管理所有功能模块的makefile。这个makefile负责主函数的编译链接工作。

这里给出一个用我写的Makefile框架管理工程的例子。可对比后面完整项目工程框架,实际使用中只需要进行简单配置即可。

Makfile实现

先写一个最简单的,能把整个工程编译出来。再考虑后续makefile的简洁,易配置等特性。
cJSON

build = ../build/cJSON
CFLAGS = $(CFLAGS_ENV)
INCLUDE = -I./include -I./src
src = $(wildcard ./src/*.c)
obj = $(src:.c=.o)

lib/libcJSON.a:$(addprefix $(build)/, $(obj))
	ar -rc $@ $^

$(addprefix $(build)/, %.o):%.c
	$(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@

.PHONY: clean
clean: 
	-rm $(build)/src/*.o ./lib/*.a
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

gsoap

build = ../build/gsoap
INCLUDE = -I../openssl/include -I./include -I./src
CFLAGS = -g -fPIC -DWITH_DOM -DWITH_OPENSSL -DWITH_NONAMESPACE -DDBUG -DWITH_NO_C_LOCALE $(CFLAGS_ENV)
src = $(wildcard ./src/*.c)
obj = $(src:.c=.o)

lib/libgsoap.a:$(addprefix $(build)/, $(obj))
	ar -rc $@ $^ 

$(addprefix $(build)/, %.o):%.c
	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@

.PHONY: clean
clean:
	-rm $(build)/src/*.o ./lib/*.a
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

onvif

build = ../build/onvif
INCLUDE = -I/usr/local/ssl/include -I./include -I./src -I../gsoap/include -I../cJSON/include
CFLAGS = -g -fPIC -DWITH_DOM -DWITH_OPENSSL -DWITH_NONAMESPACE -DDBUG -DWITH_NO_C_LOCALE $(CFLAGS_ENV)
src = $(wildcard ./src/*.c)
obj = $(src:.c=.o)

lib/libonvif.a:$(addprefix $(build)/, $(obj))
	ar -rc $@ $^

$(addprefix $(build)/, %.o):%.c
	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@

.PHONY: clean
clean:
	-rm $(build)/src/*.o ./lib/*.a
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

主函数makefile

LDLAGS = -lpthread -ldl -lm

main: gsoap/lib/libgsoap.a  onvif/lib/libonvif.a openssl/lib/libssl.a openssl/lib/libcrypto.a cJSON/lib/libcJSON.a 
	$(CC) -o $@ -Xlinker "-(" $^ -Xlinker "-)" $(LDLAGS)
	
gsoap/lib/libgsoap.a:gsoap/src/*.c
	cd gsoap && make && cd ..

onvif/lib/libonvif.a:onvif/src/*.c
	cd onvif && make && cd ..

cJSON/lib/libcJSON.a:cJSON/src/*.c
	cd cJSON && make && cd .. 

.PHONY: clean
clean:
	cd gsoap && make clean && cd ../onvif && make clean && cd ../cJSON && make clean
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
环境变量设置

build/目录为空,无法添加到远程仓库。通过这是环境变量来实现选择编译器和创建build/目录。

#!/bin/bash

#export CC=arm-himix100-linux-gcc
export CC=gcc
echo ">> [toolchain] $CC"

export CFLAGS_ENV="-ffunction-sections"
# -Wall -O2 

export obj_dir=$(ls -l | grep "^d" | awk '{print $9}' | sed 's/build//g')
for i in $obj_dir;
do
    if [ ! -d "./build/$i/src" ]; then
        mkdir -p ./build/$i/src
    fi
done

if [ $CC == "arm-himix100-linux-gcc" ]; then
    cp ./openssl/lib_arm_gcc/*.a ./openssl/lib
elif [ $CC == "gcc" ]; then
    cp ./openssl/lib_gcc/*.a ./openssl/lib
fi
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
修改优化makefile

上面的makefile文件已经能把工程编译出来了,修改.c文件,会重新编译对应的.c。但是如果我们修改头文件,运行make是不会有任何更新。所以需要在makefile里面增加.h的依赖关系。
鉴于前面都是所有文件编译都是自动识别的,考虑到如果工程很大,手动输入文件名称是一件很笨的事,需要用makefile来自动生成头文件的依赖关系。
原理:通过gcc -MM main.c命令,可以得到main.c这个文件所依赖的其它文件。如:

#include <stdio.h>
#include "test.h"
#include "main.h"
  • 1
  • 2
  • 3

那么,生成main.o所依赖的文件就包括main.ctest.h,main.h。格式如下:

main.o: main.c test.h main.h
  • 1

显然这是我们需要的依赖关系,而且这个依赖关系很完美。那么makefile是如何做的呢?
makefile通过这个命令得到依赖关系,然后把这个依赖关系保存到对应的.d文件中,在需要的地方进行导入。在保存之前,由于后面会生成.d文件,.d文件也应该随着.c导入头文件的变化而变化。所以.d是依赖于.c的,因此,makefile会对命令得到的依赖关系进行简单的修改:

main.o main.d : main.c test.h main.h
  • 1

这个依赖关系等价于:

main.o: main.c test.h main.h
main.d: main.c test.h main.h 
  • 1
  • 2

这里对于.o和.d目标的生成,运行makefile的匹配符号来完成。我看网上的教程都是不带前缀的。不带前缀会使我们将.c和.d和.o分开存放时造成错误。当对obj和dep添加前缀的话,又会导致匹配失败。所以还是在匹配的时候,通过addprefix来处理前缀问题。
至于.d文件的作用,前面已经讲了,在.c修改导入头文件后,依赖关系改变了,这个时候就是通过这个.d文件来动态的表示改变的依赖关系。否则,如果依赖关系一直不变,那么我在main.c中又导入了fun.h,那么我修改fun.h的话,这个时候运行make,那么将不会有任何更新。

通过这个方法,对上面的makefile进行修改。
cJSON


target := libcJSON.a
build := ../build/cJSON
outdir := lib
srcdir := src
INCLUDE := -I./include -I./src
CFLAGS := $(CFLAGS_ENV)

src := $(wildcard $(srcdir)/*.c)
obj := $(src:.c=.o)
dep := $(src:.c=.d)

$(outdir)/$(target):$(addprefix $(build)/, $(obj)) 
	ar -rc $@ $^

$(addprefix $(build)/, %.o):%.c 
	$(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@

$(addprefix $(build)/, %.d): %.c
	@set -e; rm -f $@; \
	$(CC) -MM $(CPPFLAGS) $(INCLUDE) $< > $@.$$$$; \
	sed 's,\($(*F)\)\.o[ :]*,$(build)/$(<D)/\1.o $@ : ,g' < $@.$$$$ > $@; \
	rm -f $@.$$$$

include $(addprefix $(build)/, $(dep))

.PHONY: clean
clean: 
	-rm $(addprefix $(build)/, $(dep)) $(addprefix $(outdir)/, $(target)) $(addprefix $(build)/, $(obj))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

gsoap


target := libgsoap.a
build := ../build/gsoap
outdir := lib
srcdir := src
INCLUDE := -I../openssl/include -I./include -I./src
CFLAGS := -g -fPIC -DWITH_DOM -DWITH_OPENSSL -DWITH_NONAMESPACE -DDBUG -DWITH_NO_C_LOCALE $(CFLAGS_ENV)

src := $(wildcard $(srcdir)/*.c)
obj := $(src:.c=.o)
dep := $(src:.c=.d)

$(outdir)/$(target):$(addprefix $(build)/, $(obj))
	ar -rc $@ $^ 

$(addprefix $(build)/, %.o):%.c
	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@

$(addprefix $(build)/, %.d): %.c
	@set -e; rm -f $@; \
	$(CC) -MM $(CPPFLAGS) $(INCLUDE) $< > $@.$$$$; \
	sed 's,\($(*F)\)\.o[ :]*,$(build)/$(<D)/\1.o $@ : ,g' < $@.$$$$ > $@; \
	rm -f $@.$$$$

include $(addprefix $(build)/, $(dep))

.PHONY: clean
clean:
	-rm $(addprefix $(build)/, $(dep)) $(addprefix $(outdir)/, $(target)) $(addprefix $(build)/, $(obj))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

onvif


target := libonvif.a
build := ../build/onvif
outdir := lib
srcdir := src
INCLUDE := -I/usr/local/ssl/include -I./include -I./src -I../gsoap/include -I../cJSON/include
CFLAGS := -g -fPIC -DWITH_DOM -DWITH_OPENSSL -DWITH_NONAMESPACE -DDBUG -DWITH_NO_C_LOCALE $(CFLAGS_ENV)

src := $(wildcard $(srcdir)/*.c)
obj := $(src:.c=.o)
dep := $(src:.c=.d)

$(outdir)/$(target):$(addprefix $(build)/, $(obj))
	ar -rc $@ $^

$(addprefix $(build)/, %.o):%.c
	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
	
$(addprefix $(build)/, %.d): %.c
	@set -e; rm -f $@; \
	$(CC) -MM $(CPPFLAGS) $(INCLUDE) $< > $@.$$$$; \
	sed 's,\($(*F)\)\.o[ :]*,$(build)/$(<D)/\1.o $@ : ,g' < $@.$$$$ > $@; \
	rm -f $@.$$$$

include $(addprefix $(build)/, $(dep))

.PHONY: clean
clean:
	-rm $(addprefix $(build)/, $(dep)) $(addprefix $(outdir)/, $(target)) $(addprefix $(build)/, $(obj))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

上面修改后的makefile支持我们修改.h文件后对工程对应的编译更新。
并且我用了很多变量。运用变量编写makefile非常的有利于我们对makefile的修改维护。
并且会让我们makefile看起来更加的清晰。

由于用了很多变量,这3个makefile的很大一部分内容都是一样。这使我们可以用makefile的include
将相同的内容写到另外一个makefile中,然后通过include将那个makefile导入。这个运用和C语言的#define宏定义类似。会对文本原样导入。
这样就得到最终的三个看起来很简洁的4个makefile。
cJSON

target := libcJSON.a
build := ../build/cJSON
outdir := lib
srcdir := src
make_run_mk_dir := ..
INCLUDE := -I./include -I./src
CFLAGS := $(CFLAGS_ENV)

include $(make_run_mk_dir)/make_run.mk

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

gsoap

target := libgsoap.a
build := ../build/gsoap
outdir := lib
srcdir := src
make_run_mk_dir := ..
INCLUDE := -I../openssl/include -I./include -I./src
CFLAGS := -g -fPIC -DWITH_DOM -DWITH_OPENSSL -DWITH_NONAMESPACE -DDBUG -DWITH_NO_C_LOCALE $(CFLAGS_ENV)

include $(make_run_mk_dir)/make_run.mk
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

onvif

target := libonvif.a
build := ../build/onvif
outdir := lib
srcdir := src
make_run_mk_dir := ..
INCLUDE := -I/usr/local/ssl/include -I./include -I./src -I../gsoap/include -I../cJSON/include
CFLAGS := -g -fPIC -DWITH_DOM -DWITH_OPENSSL -DWITH_NONAMESPACE -DDBUG -DWITH_NO_C_LOCALE $(CFLAGS_ENV)

include $(make_run_mk_dir)/make_run.mk
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

make_run.mk

src := $(wildcard $(srcdir)/*.c)
obj := $(src:.c=.o)
dep := $(src:.c=.d)

$(outdir)/$(target):$(addprefix $(build)/, $(obj))
	ar -rc $@ $^ 

$(addprefix $(build)/, %.o):%.c
	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@

$(addprefix $(build)/, %.d): %.c
	@set -e; rm -f $@; \
	$(CC) -MM $(CPPFLAGS) $(INCLUDE) $< > $@.$$$$; \
	sed 's,\($(*F)\)\.o[ :]*,$(build)/$(<D)/\1.o $@ : ,g' < $@.$$$$ > $@; \
	rm -f $@.$$$$

include $(addprefix $(build)/, $(dep))

.PHONY: clean
clean:
	-rm $(addprefix $(build)/, $(dep)) $(addprefix $(outdir)/, $(target)) $(addprefix $(build)/, $(obj))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这样就非常的简单明了了。我们只需要修改targetbuildCFLAGSINCLUDE即可。剩下的问题makefile会帮我自动处理。

让Makefile变得更好

通过上面的内容,可以自己来定义的Makefile的结构。接下来我定义了一下我的工程的Makefile的结构,是makefile使用起来更加的容易。
通过前面Makefile的编写,整个Makefile功能已经很完善了,能够处理我们一般的问题。
现在,通过修改工程的结构,让我们来更简单的使用Makefile。并且在配置Makefile的时候能够更加集中的处理。将需要配置的内容放到Makefile的最顶层和最底层。最顶层的内容存放:通用的配置和各个需要编译的模块内容。最底层存放:编译处理的具体实施。中间的Makefile只是做一个过度作用,连接顶层目录和Makefile和底层路径的Makefile。
这样做,整个Makefile结构更加的清晰明了,更易于配置。
我的工程放在github上了。
工程中的所有.c和.h已经删除,只保留了结构和Makefile,供参考。
这里展示部分makefile内容,整个工程makefile结构请参考上面的github链接。
顶层makefile

all: 
	@make -C $(MOD_DIR)
	@make -C $(APP_DIR)
	@echo "------------------------------"
	@echo "make all done."
	@echo "------------------------------"
	

.PHONY: clean gsoap_clean onvif_clean cJSON_clean clean_all

clean_all: clean
	-@rm -rf $(BUILD_DIR)

clean:
	-@make -C $(APP_DIR) clean
	-@make -C $(MOD_DIR) clean
	@echo "------------------------------"
	@echo "clean all doen."
	@echo "------------------------------"

gsoap_clean:
	-@make -C $(MOD_DIR) gsoap_clean

onvif_clean:
	-@make -C $(MOD_DIR) onvif_clean

cJSON_clean:
	-@make -C $(MOD_DIR) cJSON_clean
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

生成程序makefile

#------------------------------
# 生成程序名称
#------------------------------
target := main

#------------------------------
# 生成程序输出路径
#------------------------------
outdir := $(ROOT_DIR)

#------------------------------
# .c源文件
#------------------------------
src := $(wildcard *.c)

#------------------------------
# 链接参数
#------------------------------
LDLAGS := -lpthread -ldl -lm

#------------------------------
# 链接时需要的头文件
#------------------------------
INCLUDE := -I$(MOD_DIR)/onvif/include

#------------------------------
# 模块路径
#------------------------------
MOD += cJSON
MOD += gsoap
MOD += onvif
MOD += openssl

#------------------------------
# 链接时需要的库
#------------------------------
LIB += $(foreach d, $(addsuffix /lib, $(addprefix $(MOD_DIR)/, $(MOD))), $(wildcard $(d)/*.a))

all: $(outdir)/$(target)

$(outdir)/$(target): $(LIB) $(src)
	$(CC) -o $(outdir)/$(target) $(src) $(INCLUDE) -Xlinker "-(" $(LIB) -Xlinker "-)" $(LDLAGS)

.PHONY: clean
clean:
	-@rm -f $(outdir)/$(target)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/292890
推荐阅读
相关标签
  

闽ICP备14008679号