python编写makefile_用python写makefile

本文介绍了如何使用Python脚本来生成makefile,特别是在C/C++项目中,当源文件分布在多个文件夹下时。脚本通过递归搜索源文件,创建对应的编译规则,并自动管理目标文件的生成。此方法避免了手动维护复杂的makefile。

温馨提示:阅读本文的同学最好能了解makefile和python的编写规则。

不懂的同学能够先保存在收藏夹。以便日后查看。

事实上之前我一直非常懒,我不想了解makefile规则。由于在linux下开发我一直使用Qt creator。(非常多时候正是一些“懒人”的创造力。解放了我们的双手,显然如今我们还须要用双手写makefile)。Qt creator是一个非常好的IDE。并且能够跨平台开发。可是相比VS,显然还是不够优秀。

因此非常多开发人员都会选择在Windows下开发C/C++程序,然后部署在Linux下运行。当然我也不例外。所以近期花了几个晚上了解makefile的编写规则。

開始的时候。我參照网上一些makefile的样例,写了一个初版的makefile。然而这个makefile在编译我的project的时候报错。

主要出错体如今:

%.o: %.cpp

$(CXX) -fpic -c $(INCPATH) $< -o $@

当然能够写成

$(objdir)/%.o:$(srcdir)/%.cpp

$(CXX) -fpic -c $(INCPATH) $< -o $@

原因在于:

1、.o文件与.cpp文件处于不同的文件夹下。

2、不同的.o文件或不同的.cpp文件处于不同的文件夹下。

这时我找到两种解决方法:

1、就是用VPATH这个特殊变量,可是我不可能将全部要包括的文件夹都一一手动包括进来,于是我放弃。

2、就是把全部的编译规则列举出来。

我终于选择另外一种解决方法。

由于之前遇到这个困难时,我特意去了解Qt生成的makefile(事实上这个makefile是根据.proproject文件生成的)。而这个makefile正是将全部的编译规则都列举出来。

于是就有以下这个python脚本。事实上開始的时候我想用shell来做这一步工作的,可是我看到sed和awk。我头都晕,之前还一直抵触学习sed和awk。因此最后选择了python。

#encoding: utf-8

import os

import os.path

import sys

#sys.exit(0);

#########################################################################################################################

#

#本脚本的作用是:通过配置必要的信息,用python来生成makefile。

(技术支持:www.guimigame.com)

#@FILENAME 运行脚本输出makefile文件名称

#@BIN 生成可运行文件名称

#@SUFFIX 源文件后缀

#@ROOTPATH“根”文件夹路径(脚本工作文件夹的上一层)

#@PWD当前工作文件夹

#@WD 工作文件夹。假设程序有多个工作文件夹请一一用append加上

#@BINDIR可运行文件输出文件夹

#@OBJDIR中间文件输出文件夹

#@INCROOTPATH头文件包括路径的“根路径”,方便INCPATH的编写

#@LIBROOTPATH 包括库的“根”路径。方便LIBS的编写

#@INCPATH 头文件包括路径

#@SYSLIBS 包括的系统库

#@LIBS编译程序须要包括的库

# @CXX一般填写gcc/g++

#@FLAGSgcc/g++的编译标志

#

#########################################################################################################################

FILENAME = 'makefile';

BIN= "DatabaseServer";

SUFFIX = ".cpp";

ROOTPATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)));

PWD = os.getcwd();

WD= [];

WD.append(PWD);

WD.append(ROOTPATH + "/common");

BINDIR= PWD + "/Bin/";

OBJDIR= BINDIR + "obj/";

INCROOTPATH= "-I " + ROOTPATH;

LIBROOTPATH = "-L " + ROOTPATH;

INCPATH = INCROOTPATH + "/common" + " " + INCROOTPATH + "/lib/include";

SYSLIBS= " -lmysqlclient -lpthread"

LIBS= LIBROOTPATH + "/lib/linux " + "-lTimeManager -lServerConfig -lGameSocket -lCommon -lTinyxml" + SYSLIBS;

CXX= "g++";

FLAGS= '-g -Wall';

#########################################################################################################################

#

#下面不须要再配置

#

#########################################################################################################################

OBJFILE= '';

OBJ2SRC= [];

SOURCES= "";

def SearchFiles(path):

global OBJFILE;

global OBJ2SRC;

global SOURCES;

global SUFFIX;

listFile = os.listdir(path);

for file in listFile:

if os.path.isdir(os.path.join(path, file)):

SearchFiles(os.path.join(path, file));

elif file.endswith(SUFFIX) > 0:

OBJFILE = file;

OBJFILE = OBJFILE.replace(SUFFIX,'.o');

OBJ2SRC.append([OBJDIR + OBJFILE,path + "/" + file]);

SOURCES += path + "/" + file + " ";

for dir in WD:

SearchFiles(dir);

if os.path.exists(FILENAME):

os.remove(FILENAME);

f = open(FILENAME,'w');

f.write("PWD = " + PWD + "\n");

f.write("CXX = " + CXX + "\n");

f.write("INCPATH= " + INCPATH + "\n");

f.write("LIBS = " + LIBS + "\n");

f.write("BINDIR= " + BINDIR +"\n");

f.write("OBJDIR= " + OBJDIR + "\n");

f.write("BIN = " + BIN + "\n");

f.write("SOURCES= " + SOURCES+ "\n");

f.write("SOURCEFILES= $(notdir $(SOURCES))\n");

f.write("OBJECTS= $(addprefix $(OBJDIR), $(patsubst %.cpp,%.o,$(SOURCEFILES)))\n");

f.write("FLAGS= " + FLAGS + "\n");

f.write("\n");

f.write("all:makedir $(OBJECTS)\n");

f.write("$(CXX) $(FLAGS) $(INCPATH) -o $(BIN) $(OBJECTS) $(LIBS);\n");

f.write("\n");

f.write("makedir:\n");

f.write('$(shell if [ -n "$(OBJDIR)" -a ! -e "$(OBJDIR)" ];then mkdir -p $(OBJDIR); fi)\n');

f.write('$(shell if [ -n "$(BINDIR)" -a ! -e "$(BINDIR)" ];then mkdir -p $(BINDIR); fi)\n');

f.write("\n");

for val in OBJ2SRC:

f.write(val[0] + ":" + val[1] +"\n");

f.write("rm -f $@\n");

f.write("$(CXX) -fpic -c $(INCPATH) $< -o $@\n");

f.write("\n");

f.close();

os.system("make");

os.system("mv " + BIN + " " + BINDIR);

os.system("cd " + OBJDIR + ";rm -f *.o");

怎样编写makefile和python,这里不作说明。由于这篇文章不是makefile和python的教程。下面要说明的是SearchFiles函数。

通过遍历之前设定的project工作文件夹。调用SearchFiles遍历该文件夹下全部的源文件(.cpp),及设定目标文件(.o)的绝对路径,终于是tuple的形式保存到OBJ2SRC数组中。还有的是将全部源文件保存在SOURCES中。当然这个过程中会递归遍历全部子文件夹,查找到全部的源文件。终于在for val in OBJ2SRC:遍历全部的数据;列出全部的源文件(.cpp)生成所相应的目标文件(.o)。将编译规则写进makefile。

这是我要编译的project。当然截图仅仅是其中一部分。

这个project须要包括的文件除了在DatabaseServer下,还要包括在../common其中(脚本中代码WD.append(ROOTPATH + "/common");)。

我截图是为了证明。这个脚本是可行的。有人可能会说为什么不写一个測试样例。

事实上我想说。非常多时候要弄懂一些技术。动手去做或许是最好的方法。假设你有什么问题,欢迎与我讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值