最近遇到需要将vs2010的c++项目移植到linux下面的问题,由于项目中分了很多个子目录,如何写Makefile是一个很头疼的问题,不过还好,经过一番折腾,还是实现了初步的要求,下面给出一个嵌套目录的Makefile示例:
先说一些必要的知识点:
1.在linux下编译c++项目,我目前知道的有下面几种方法:
1.1 在命令行运行类似 g++ -c main.cpp -o mian.o 命令,100个cpp文件,运行100条对应的命令。(好累 )
1.2 将上面的100条命令,全部保存到一个shell脚本中,然后运行 sh run.sh
1.3 利用Makefile文件,来编译上面100个cpp文件(此文采用这种方法来编译)
1.4 利用libtool来编译
2.编写Makefile有很多规则,网上有很多介绍这方面的资料。
3.linux的强大之处在于正则表达式和通配符,在Makefile里面,
src_files = $(wildcard *.cpp) 变量src_files表示所有.cpp文件
objects = $(patsubst %.cpp, %.o, $(src_files))变量objects表示所有.o文件
4.每个目录都应该有一个Makefile文件,可以在Makefile里面嵌入shell的for循环命令,来调用嵌套目录的Makefile
--------------------------------------------------
本示例的目录结构为:
[root@localhost test]$ tree
.
├── dir1
│ ├── dir11
│ │ ├── func11.cpp
│ │ ├── func11.h
│ │ └── Makefile
│ ├── dir12
│ │ ├── func12.cpp
│ │ ├── func12.h
│ │ └── Makefile
│ ├── func1.cpp
│ ├── func1.h
│ └── Makefile
├── main.cpp
└── Makefile
有4个目录,所以有4个Makefile,其中和mian.cpp在同一目录的Makefile,负责调用剩下的Makefile。
// ./main.cpp
#include <stdio.h>
#include "dir1/func1.h"
#include "dir1/dir11/func11.h"
#include "dir1/dir12/func12.h"
int main(int argc, char * argv[])
{
func1();
func11();
func12();
return 0;
}
// ./dir1/func1.h
void func1();
// ./dir1/func1.cpp
#include <stdio.h>
#include "func1.h"
void func1()
{
printf("[%s:%s] Hello World!\n", __FILE__, __FUNCTION__);
}
// ./dir1/dir11/func11.h
void func11();
// ./dir1/dir11/func11.cpp
#include <stdio.h>
#include "func11.h"
void func11()
{
printf("[%s:%s] Hello World!\n", __FILE__, __FUNCTION__);
}
// ./dir1/dir12/func12.h
void func12();
// ./dir1/dir12/func12.cpp
#include <stdio.h>
#include "func12.h"
void func12()
{
printf("[%s:%s] Hello World!\n", __FILE__, __FUNCTION__);
}
--------------各个目录对应的Makefile如下-------------------------
注意:由于CSDN显示的原因,"$ $target " 实际为 "$$target","$ $subdir"也是一样
// ./Makefile
GCC = gcc
CC = g++
is_debug = 0
DEBUG =
prefix = ./build_linux/x64/Release
ifeq ($(is_debug), 1)
DEBUG = -g
prefix = ./build_linux/x64/Debug
else
DEBUG = -O3
prefix = ./build_linux/x64/Release
endif
#----------------------------------
CFLAGS = -c -Wall $(DEBUG) -I. -I/usr/include
LIBS = -L/usr/lib64 -ldl -lpthread
#----------------------------------
out_exe = main
objects = main.o
libs_a = \
dir1/libfunc1.a \
dir1/dir11/libfunc11.a \
dir1/dir12/libfunc12.a
SUBDIRS = \
dir1 \
.
#----------------------------------
all:
$(MAKE) $(AM_MAKEFLAGS) all-recursive
#----------------------------------
all-am: Makefile $(out_exe)
$(out_exe): $(objects) $(libs_a)
rm -f $(out_exe)
$(CC) -o $(out_exe) $(objects) $(libs_a) $(LIBS)
$(objects): %.o: %.cpp
$(CC) $(CFLAGS) $< -o $@
#----------------------------------
recursive_targets = all-recursive clean-recursive
$(recursive_targets):
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; \
for subdir in $$list; do \
echo "Making $ $target in $ $subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $ $subdir && $(MAKE) $(AM_MAKEFLAGS) $ $local_target is_debug=$(is_debug)); \
done;
#----------------------------------
clean: clean-recursive
clean-am:
rm -f *.o $(out_exe)
#----------------------------------
.PHONY: all $(recursive_targets) clean
// ./dir1/Makefile
GCC = gcc
CC = g++
AR = ar
ARFLAGS = crs
is_debug = 0
DEBUG =
ifeq ($(is_debug), 1)
DEBUG = -g
else
DEBUG = -O3
endif
CFLAGS = -c -Wall $(DEBUG) -I. -I/usr/include
#----------------------------------
libs_a = \
dir11/libfunc11.a \
dir12/libfunc12.a
SUBDIRS = \
dir11 \
dir12 \
.
lib_a = libfunc1.a
src_files = $(wildcard *.cpp)
objects = $(patsubst %.cpp, %.o, $(src_files))
#----------------------------------
all:
$(MAKE) $(AM_MAKEFLAGS) all-recursive
#----------------------------------
all-am: Makefile $(lib_a)
#----------------------------------
$(lib_a): $(objects)
-rm -f $(lib_a)
$(AR) $(ARFLAGS) $(lib_a) $(objects)
$(objects): %.o: %.cpp
$(CC) $(CFLAGS) $< -o $@
#----------------------------------
recursive_targets = all-recursive clean-recursive
$(recursive_targets):
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; \
for subdir in $$list; do \
echo "Making $ $target in $ $subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $ $subdir && $(MAKE) $(AM_MAKEFLAGS) $ $local_target is_debug=$(is_debug)); \
done;
#----------------------------------
clean: clean-recursive
clean-am:
rm -f *.o $(lib_a)
#----------------------------------
.PHONY: all $(recursive_targets) clean
// ./dir1/dir11/Makefile
GCC = gcc
CC = g++
AR = ar
ARFLAGS = crs
is_debug = 0
DEBUG =
ifeq ($(is_debug), 1)
DEBUG = -g
else
DEBUG = -O3
endif
CFLAGS = -c -Wall $(DEBUG) -I. -I/usr/include
#----------------------------------
lib_a = libfunc11.a
src_files = $(wildcard *.cpp)
objects = $(patsubst %.cpp, %.o, $(src_files))
#----------------------------------
all: $(lib_a)
$(lib_a): $(objects)
-rm -f $(lib_a)
$(AR) $(ARFLAGS) $(lib_a) $(objects)
$(objects): %.o: %.cpp
$(CC) $(CFLAGS) $< -o $@
#----------------------------------
clean:
rm -f *.o $(lib_a)
#----------------------------------
.PHONY: all clean
// ./dir1/dir12/Makefile
GCC = gcc
CC = g++
AR = ar
ARFLAGS = crs
is_debug = 0
DEBUG =
ifeq ($(is_debug), 1)
DEBUG = -g
else
DEBUG = -O3
endif
CFLAGS = -c -Wall $(DEBUG) -I. -I/usr/include
#----------------------------------
lib_a = libfunc12.a
src_files = $(wildcard *.cpp)
objects = $(patsubst %.cpp, %.o, $(src_files))
#----------------------------------
all: $(lib_a)
$(lib_a): $(objects)
-rm -f $(lib_a)
$(AR) $(ARFLAGS) $(lib_a) $(objects)
$(objects): %.o: %.cpp
$(CC) $(CFLAGS) $< -o $@
#----------------------------------
clean:
rm -f *.o $(lib_a)
#----------------------------------
.PHONY: all clean
----------------1.编译Release版本--------------------------
运行 make 或 make is_debug=0
[fujin@localhost test3]$ make
make all-recursive
make[1]: Entering directory `/home/fujin/work/test/make_file/test3'
dot_seen=no; \
target=`echo all-recursive | sed s/-recursive//`; \
list='dir1 .'; \
for subdir in $list; do \
echo "Making $target in $subdir"; \
if test "$subdir" = "."; then \
dot_seen=yes; \
local_target="$target-am"; \
else \
local_target="$target"; \
fi; \
(cd $subdir && make $local_target is_debug=0); \
done;
Making all in dir1
make[2]: Entering directory `/home/fujin/work/test/make_file/test3/dir1'
make all-recursive
make[3]: Entering directory `/home/fujin/work/test/make_file/test3/dir1'
dot_seen=no; \
target=`echo all-recursive | sed s/-recursive//`; \
list='dir11 dir12 .'; \
for subdir in $list; do \
echo "Making $target in $subdir"; \
if test "$subdir" = "."; then \
dot_seen=yes; \
local_target="$target-am"; \
else \
local_target="$target"; \
fi; \
(cd $subdir && make $local_target is_debug=0); \
done;
Making all in dir11
make[4]: Entering directory `/home/fujin/work/test/make_file/test3/dir1/dir11'
g++ -c -Wall -O3 -I. -I/usr/include func11.cpp -o func11.o
rm -f libfunc11.a
ar crs libfunc11.a func11.o
make[4]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1/dir11'
Making all in dir12
make[4]: Entering directory `/home/fujin/work/test/make_file/test3/dir1/dir12'
g++ -c -Wall -O3 -I. -I/usr/include func12.cpp -o func12.o
rm -f libfunc12.a
ar crs libfunc12.a func12.o
make[4]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1/dir12'
Making all in .
make[4]: Entering directory `/home/fujin/work/test/make_file/test3/dir1'
g++ -c -Wall -O3 -I. -I/usr/include func1.cpp -o func1.o
rm -f libfunc1.a
ar crs libfunc1.a func1.o
make[4]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1'
make[3]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1'
make[2]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1'
Making all in .
make[2]: Entering directory `/home/fujin/work/test/make_file/test3'
g++ -c -Wall -O3 -I. -I/usr/include main.cpp -o main.o
rm -f main
g++ -o main main.o dir1/libfunc1.a dir1/dir11/libfunc11.a dir1/dir12/libfunc12.a -L/usr/lib64 -ldl -lpthread
make[2]: Leaving directory `/home/fujin/work/test/make_file/test3'
make[1]: Leaving directory `/home/fujin/work/test/make_file/test3'
运行 make is_debug=1
[fujin@localhost test3]$ make is_debug=1
make all-recursive
make[1]: Entering directory `/home/fujin/work/test/make_file/test3'
dot_seen=no; \
target=`echo all-recursive | sed s/-recursive//`; \
list='dir1 .'; \
for subdir in $list; do \
echo "Making $target in $subdir"; \
if test "$subdir" = "."; then \
dot_seen=yes; \
local_target="$target-am"; \
else \
local_target="$target"; \
fi; \
(cd $subdir && make $local_target is_debug=1); \
done;
Making all in dir1
make[2]: Entering directory `/home/fujin/work/test/make_file/test3/dir1'
make all-recursive
make[3]: Entering directory `/home/fujin/work/test/make_file/test3/dir1'
dot_seen=no; \
target=`echo all-recursive | sed s/-recursive//`; \
list='dir11 dir12 .'; \
for subdir in $list; do \
echo "Making $target in $subdir"; \
if test "$subdir" = "."; then \
dot_seen=yes; \
local_target="$target-am"; \
else \
local_target="$target"; \
fi; \
(cd $subdir && make $local_target is_debug=1); \
done;
Making all in dir11
make[4]: Entering directory `/home/fujin/work/test/make_file/test3/dir1/dir11'
g++ -c -Wall -g -I. -I/usr/include func11.cpp -o func11.o
rm -f libfunc11.a
ar crs libfunc11.a func11.o
make[4]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1/dir11'
Making all in dir12
make[4]: Entering directory `/home/fujin/work/test/make_file/test3/dir1/dir12'
g++ -c -Wall -g -I. -I/usr/include func12.cpp -o func12.o
rm -f libfunc12.a
ar crs libfunc12.a func12.o
make[4]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1/dir12'
Making all in .
make[4]: Entering directory `/home/fujin/work/test/make_file/test3/dir1'
g++ -c -Wall -g -I. -I/usr/include func1.cpp -o func1.o
rm -f libfunc1.a
ar crs libfunc1.a func1.o
make[4]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1'
make[3]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1'
make[2]: Leaving directory `/home/fujin/work/test/make_file/test3/dir1'
Making all in .
make[2]: Entering directory `/home/fujin/work/test/make_file/test3'
g++ -c -Wall -g -I. -I/usr/include main.cpp -o main.o
rm -f main
g++ -o main main.o dir1/libfunc1.a dir1/dir11/libfunc11.a dir1/dir12/libfunc12.a -L/usr/lib64 -ldl -lpthread
make[2]: Leaving directory `/home/fujin/work/test/make_file/test3'
make[1]: Leaving directory `/home/fujin/work/test/make_file/test3'
--------------3.运行结果-----------------------
[fujin@localhost test3]$ tree
.
├── dir1
│ ├── dir11
│ │ ├── func11.cpp
│ │ ├── func11.h
│ │ ├── func11.o
│ │ ├── libfunc11.a
│ │ └── Makefile
│ ├── dir12
│ │ ├── func12.cpp
│ │ ├── func12.h
│ │ ├── func12.o
│ │ ├── libfunc12.a
│ │ └── Makefile
│ ├── func1.cpp
│ ├── func1.h
│ ├── func1.o
│ ├── libfunc1.a
│ └── Makefile
├── main
├── main.cpp
├── main.o
└── Makefile
3 directories, 19 files
[fujin@localhost test3]$ ./main
[func1.cpp:func1] Hello World!
[func11.cpp:func11] Hello World!
[func12.cpp:func12] Hello World!