您的位置:首页 > 运维架构 > Linux

linux Makefile : 编译包含非当前目录的工程

2017-09-24 20:19 357 查看

前几天和同事聊起重构, 他想将工程结构调整下, 将每个工程和依赖的基础代码都分开.

每个工程和基础代码都有单独的版本文件夹. 不同版本在Makefile中可以方便的包含. e.g. 下个版本要用1.0.1.1版的基础代码和逻辑代码, 当前版本要连接1.0.0.1版的基础代码和逻辑代码.

这样, 当前简单的Makefile就不适用了, 当前的Makefile只能编译当前目录和子目录下的实现.

今天将这个实验做了.

总体目标 : 如果工程中添加了非当前目录的编译内容, 也不要使修改Makefile的工作量太大. 因为对Makefile的编写还是个小白, 做到新添加了非当前目录编译内容, 能少改些Makefile就可以接受了.

为了可以在低版本linux内核上运行, 使用了-std=c++98的选项.

实验

重构后的目录结构

类似于下图, 目录结构为 => 工程或子工程(或依赖的公用实现)名称/工程版本/子工程文件夹名称/具体的文件名称

最后要执行的Makefile在主工程中, e.g. 1_7/1.0.0.1/Makefile

├─1_7
│  └─1.0.0.1
│      │  main.cpp
│      │  Makefile
│      │  readme.txt
│      │
│      └─empty_dir
├─3rd
│  └─1.0.0.1
├─base
│  └─1.0.0.1
│      │  base_header.h
│      │
│      ├─file
│      ├─net
│      ├─process
│      └─string
│              helper_string.cpp
│              helper_string.h
│
└─business
└─1.0.0.1
│  business_header.h
│
└─string


Makefile

# ==============================================================================
# makefile
#   lostspeed 2017-09-24
# ==============================================================================
# ------------------------------------------------------------------------------
# all code on PROG_VER's dir
# e.g. base/PROG_VER/file
# myprog/PROG_VER/main.cpp
# myprog/PROG_VER/subdir/xx.cpp
# the Makeile on myprog/PROG_VER/
PROG_VER = 1.0.0.1
LINE80 = --------------------------------------------------------------------------------
CC = g++ -std=c++98
CFLAGS = -Wall -g
BIN = case_1_7
INC = -I. -I../../base/$(PROG_VER)/ -I../../business/$(PROG_VER)/
LIBS = -lstdc++ -pthread
LIBPATH = /usr/local/lib

# DEPEND_CODE_DIR is other code not in ./ or ./xx, e.g. base code, business code
# if add a base code dir, append it to DEPEND_CODE_DIR e.g. ../xx_base/xx_type/
DEPEND_CODE_DIR = ../../base/$(PROG_VER)/ \
../../base/$(PROG_VER)/file/ \
../../base/$(PROG_VER)/net/ \
../../base/$(PROG_VER)/process/ \
../../base/$(PROG_VER)/string/ \
../../business/$(PROG_VER)/ \
../../business/$(PROG_VER)/log/ \

DEPEND_CODE_SRC = $(shell find $(DEPEND_CODE_DIR) -name '*.cpp')
DEPEND_CODE_OBJ = $(DEPEND_CODE_SRC:.cpp=.o)

# root code dir is ./'s code, e.g. main.cpp
ROOT_CODE_SRC = $(shell find ./ -name '*.cpp')
ROOT_CODE_OBJ = $(ROOT_CODE_SRC:.cpp=.o)

# if no sub code dir, must fill a sub dir exist but empty. e.g. ./empty_dir
# if have sub code dir, fill it like DEPEND_CODE_DIR
# e.g. ./xx_subdir/xx_type/
SUB_CODE_DIR = ./empty_dir
SUB_CODE_SRC = $(shell find $(SUB_CODE_DIR) -name '*.cpp')
SUB_CODE_OBJ = $(SUB_CODE_SRC:.cpp=.o)

help:
clear

@echo $(LINE80)
@echo "ROOT_CODE_SRC = " $(ROOT_CODE_SRC)
@echo "ROOT_CODE_OBJ = " $(ROOT_CODE_OBJ)

@echo "DEPEND_CODE_DIR = " $(DEPEND_CODE_DIR)
@echo "DEPEND_CODE_SRC = " $(DEPEND_CODE_SRC)
@echo "DEPEND_CODE_OBJ = " $(DEPEND_CODE_OBJ)

@echo "SUB_CODE_DIR = " $(SUB_CODE_DIR)
@echo "SUB_CODE_SRC = " $(SUB_CODE_SRC)
@echo "SUB_CODE_OBJ = " $(SUB_CODE_OBJ)

@echo "INC = " $(INC)

clean:
clear
@echo $(LINE80)
@echo make clean
rm -f $(BIN) $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)

all:$(BIN)
@echo $(LINE80)
@echo make all
chmod 777 $(BIN)
find . -name $(BIN)

$(BIN) : $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
$(CC) $(CFLAGS) -o $@ $^

.cpp.o:
$(CC) -c $(CFLAGS) $^ -o $@ $(INC) -L$(LIBPATH) $(LIBS)

rebuild:
make clean
@echo $(LINE80)
make all

rebuild_and_run:
make rebuild
@echo $(LINE80)
./$(BIN)


做实验的测试工程

这个测试代码中没有的实现, 都放在其他目录中(非主工程及其子目录, ), 在Makefile中指定路径和编译连接.

// @file 1_7.cpp
// @brief ...

#include "base_header.h"
#include "business_header.h"
#include "string/helper_string.h"

int main(int argc, char** argv)
{
int status = 0;
pid_t pid = 0;
char sz_buf[MAXLINE] = {'\0'};

printf(">> 1-7\n");

printf("# "); // show command tip char
while (NULL != fgets(sz_buf, sizeof(sz_buf), stdin)) {
if (strlen(sz_buf) > 0) {
sz_buf[strlen(sz_buf) -1] = '\0';
}

pid = fork();
printf("fork()'s PID = %d\n", pid);

if (pid < 0) {
show_err_and_quit("fork error");
} else if (0 == pid) {
printf("son process code : %s\n", sz_buf);
execlp(sz_buf, sz_buf, (char*)NULL);

// if execlp ok, can't do code below
printf("after execlp\n");
err_ret("can't execute : %s", sz_buf);
exit(127);
} else {
// this is parent fork's son process
printf("waitpid\n");
pid = waitpid(pid, &status, 0);
if (pid < 0) {
show_err_and_quit("waitpid error");
}

// ok, son process over, can continue
printf("# "); // show command tip char
}
}

exit(0);
}


工程的编译

在Makefile中弄了一个rebuild_and_run参数, 编译完, 直接可以跑起来测试.

root@debian750devmin:/home/lostspeed/dev/1_7/1.0.0.1# make rebuild_and_run


--------------------------------------------------------------------------------
make clean
rm -f case_1_7 ./main.o ../../base/1.0.0.1/string/helper_string.o ../../base/1.0.0.1/string/helper_string.o
make[2]: 警告:检测到时钟错误。您的创建可能是不完整的。
make[2]: Leaving directory `/home/lostspeed/dev/1_7/1.0.0.1'
--------------------------------------------------------------------------------
make all
find: “../../business/1.0.0.1/log/”: 没有那个文件或目录
make[2]: Entering directory `/home/lostspeed/dev/1_7/1.0.0.1'
make[2]: Warning: File `Makefile' has modification time 4.3e+04 s in the future
g++ -std=c++98 -c -Wall -g main.cpp -o main.o -I. -I../../base/1.0.0.1/ -I../../business/1.0.0.1/ -L/usr/local/lib -lstdc++ -pthread
g++ -std=c++98 -c -Wall -g ../../base/1.0.0.1/string/helper_string.cpp -o ../../base/1.0.0.1/string/helper_string.o -I. -I../../base/1.0.0.1/ -I../../business/1.0.0.1/ -L/usr/local/lib -lstdc++ -pthread
g++ -std=c++98 -Wall -g -o case_1_7 main.o ../../base/1.0.0.1/string/helper_string.o
--------------------------------------------------------------------------------
make all
chmod 777 case_1_7
find . -name case_1_7
./case_1_7
make[2]: 警告:检测到时钟错误。您的创建可能是不完整的。
make[2]: Leaving directory `/home/lostspeed/dev/1_7/1.0.0.1'
make[1]: 警告:检测到时钟错误。您的创建可能是不完整的。
make[1]: Leaving directory `/home/lostspeed/dev/1_7/1.0.0.1'
--------------------------------------------------------------------------------
./case_1_7
>> 1-7
# ^Cmake: *** [rebuild_and_run] 中断
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: