比较简单的Generic Makefile for C/C++ Program
参考网上资料写的一个简单的能够编译C/C++混合工程的Makefile【网上大多通用Makefile很长且未有解释,故写此文档】
暂未遇到问题,本人不甚精通,文件未经实际使用锤炼,如有问题请联系:liyanbin0027@163.com 墙裂欢迎指正与交流!
本Makefie需要读者有一定的Makefile基础知识
本Makefile可实现多级目录编译,使用者需要根据自己的项目自己设置,主要设置变量如下:
# CFLAGS/CXXFLAGS 用于设置编译器参数、头文件路径【包括动态库头文件路径如果有使用到】
# LDFLAGS 用于设置动态库文件所在路径【如果有使用到】
# SRCDIRS 用于设置源代码所在文件夹
# SRCEXTS 用于设置工程中用到的文件类型,比如.c .cxx
序-结果演示
首先建立文件如下:
各文件内容如下:
hello.c
/* File name: hello.c
* c source file
*/
#include "hello.h"
#include "stdio.h"
void print_hello()
{
printf("Hello, world!\n");
}
hello.h
/* File name: hello.h
* c header file
*/
#ifndef HELLO_H
#define HELLO_H
#ifdef __cplusplus
extern "C" {
#endif
void print_hello();
#ifdef __cplusplus
}
#endif
#endif
main.cxx
/* File naem: main.cxx
* c++ source file
*/
#include "hello.h"
int main()
{
print_hello();
return 0;
}
Makefile
#############################################################################
#
# Generic Makefile for C/C++ Program
#
# Author: Yanbin Lee
# Date : 2017/07/05
#============================================================================
# The C/C++ program compiler.
CC=gcc
CXX=g++
# 编译器在编译时的参数设置,包含头文件路径设置
CFLAGS:=-Wall -O2 -g
CFLAGS+=-I $(shell pwd)/include
CXXFLAGS:=-Wall -O2 -g
CXXFLAGS+=-I $(shell pwd)/include
# 库文件添加
LDFLAGS:=
LDFLAGS+=
# 指定源程序存放位置
SRCDIRS:=.
SRCDIRS+=dir
# 设置程序中使用文件类型
SRCEXTS:=.c .cxx
# 设置运行程序名
PROGRAM:=hello
#t1=$(addprefix $(SRCDIRS)/*,$(SRCEXTS))
#t2=$(foreach d,$(SRCDIRS),echo $(d))
#t3=$(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
#all:
# @echo $(t3)
SOURCES=$(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
OBJS=$(foreach x,$(SRCEXTS),$(patsubst %$(x),%.o,$(filter %$(x),$(SOURCES))))
.PHONY: all clean distclean install
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
%.o: %.cxx
$(CXX) -c $(CXXFLAGS) -o $@ $<
$(PROGRAM): $(OBJS)
ifeq ($(strip $(SRCEXTS)),.c)
$(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS)
else
$(CXX) -o $(PROGRAM) $(OBJS) $(LDFLAGS)
endif
install:
install -m 755 -D -p $(PROGRAM) ./bin
clean:
rm -f $(shell find -name "*.o")
rm -f $(PROGRAM)
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(PROGRAM)
all:
@echo $(OBJS)
本示例工程代码可到此下载:点击打开链接
获取root权限,输入make得到可执行文件hello,然后运行:
1. 部分makefile函数
该小节介绍了使用到的部分函数,完整的函数介绍可参考:
【Makefile常用函数总结】http://blog.csdn.net/ustc_dylan/article/details/6963248
filter:过滤函数
sources := foo.c bar.c baz.s ugh.h
$(filter %.c %.s,$(sources))
数返回值为“foo.c bar.c baz.s”
patsubst:模式替换函数
$(patsubst %.c,%.o,x.c.c bar.c)
#把字串“x.c.c bar.c”中以.c结尾的单词替换成以.o结尾的字符。函数的返回结果是“x.c.o bar.o”
wildcard:模式匹配文件名
在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表
foreach:循环函数
$(foreach VAR,LIST,TEXT)
执行时把“LIST”中使用空格分割的单词依次取出赋值给变量“VAR”,然后执行“TEXT”表达式
a.o b.o
string:去空格函数,去掉<string>字串中开头和结尾的空字符
$(strip a b c )
把字串“abc”去到开头和结尾的空格,结果是“abc”。
$(findstring <find>,<in> )
addprefix :加前缀函数
$(addprefix src/,foo bar)返回值是“src/foosrc/bar”
2. 难点解释
本Makefile 中比较难理解的可能是【SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))】这句,单纯从语法理解会比较难理解,可逐步拆解
测试1
文件夹下新建文件
root@ubuntu:/home/share/task002# ls
hello.c hello.h Makefile mian.cxx
Makefile:
SRCDIRS:=.
SRCEXTS:=.c .cxx
t1=$(addprefix $(SRCDIRS)/*,$(SRCEXTS))
all:
@echo $(t1)
输出:./hello.c ./mian.cxx(一开始以为输出的会是./*.c、./*cxx)
测试2
在测试1的基础上添加一个dir文件夹
SRCDIRS:=.
SRCDIRS+=dir
t2=$(foreach d,$(SRCDIRS),echo $(d))
all:
@echo $(t2)
输出:echo . echo dir【注意不是结果不是由all得到的,而是由foreach的规则输出的】
测试3
在测试2的基础上添加一个a.c文件
SRCDIRS:=.
SRCDIRS+=dir
SRCEXTS:=.c .cxx
t3=$(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
all:
@echo $(t3)
输出:./hello.c ./mian.cxx dir/a.c(单纯的去理解很难,还是自己测试一下比较合理)
测试4
同理对OBJS=$(foreach x,$(SRCEXTS),$(patsubst %$(x),%.o,$(filter %$(x),$(SOURCES))))进行处理,同时在dir目录下新建一个文件a.o
最终的输出:./hello.o dir/a.o ./mian.o
3. 注意事项
l 在windows下编辑的时候注意空格、注意Tab键、注意换行符,这些都是坑
l 时间有限,未测试添加动态库时Makefile文件是否可用