温馨提示:阅读本文的同学最好能了解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 $&#64;
当然能够写成
$(objdir)/%.o:$(srcdir)/%.cpp
$(CXX) -fpic -c $(INCPATH) $<-o $&#64;
原因在于&#xff1a;
1、.o文件与.cpp文件处于不同的文件夹下。
2、不同的.o文件或不同的.cpp文件处于不同的文件夹下。
这时我找到两种解决方法&#xff1a;
1、就是用VPATH这个特殊变量&#xff0c;可是我不可能将全部要包括的文件夹都一一手动包括进来&#xff0c;于是我放弃。
2、就是把全部的编译规则列举出来。
我终于选择另外一种解决方法。
由于之前遇到这个困难时&#xff0c;我特意去了解Qt生成的makefile(事实上这个makefile是根据.proproject文件生成的)。而这个makefile正是将全部的编译规则都列举出来。
于是就有以下这个python脚本。事实上開始的时候我想用shell来做这一步工作的&#xff0c;可是我看到sed和awk。我头都晕&#xff0c;之前还一直抵触学习sed和awk。因此最后选择了python。
#encoding: utf-8
import os
import os.path
import sys
#sys.exit(0);
#########################################################################################################################
#
#本脚本的作用是:通过配置必要的信息,用python来生成makefile。
(技术支持:www.guimigame.com)
#&#64;FILENAME 运行脚本输出makefile文件名称
#&#64;BIN 生成可运行文件名称
#&#64;SUFFIX 源文件后缀
#&#64;ROOTPATH“根”文件夹路径(脚本工作文件夹的上一层)
#&#64;PWD当前工作文件夹
#&#64;WD 工作文件夹。假设程序有多个工作文件夹请一一用append加上
#&#64;BINDIR可运行文件输出文件夹
#&#64;OBJDIR中间文件输出文件夹
#&#64;INCROOTPATH头文件包括路径的“根路径”&#xff0c;方便INCPATH的编写
#&#64;LIBROOTPATH 包括库的“根”路径。方便LIBS的编写
#&#64;INCPATH 头文件包括路径
#&#64;SYSLIBS 包括的系统库
#&#64;LIBS编译程序须要包括的库
# &#64;CXX一般填写gcc/g&#43;&#43;
#&#64;FLAGSgcc/g&#43;&#43;的编译标志
#
#########################################################################################################################
FILENAME &#61; &#39;makefile&#39;;
BIN&#61; "DatabaseServer";
SUFFIX &#61; ".cpp";
ROOTPATH &#61; os.path.dirname(os.path.dirname(os.path.abspath(__file__)));
PWD &#61; os.getcwd();
WD&#61; [];
WD.append(PWD);
WD.append(ROOTPATH &#43; "/common");
BINDIR&#61; PWD &#43; "/Bin/";
OBJDIR&#61; BINDIR &#43; "obj/";
INCROOTPATH&#61; "-I " &#43; ROOTPATH;
LIBROOTPATH &#61; "-L " &#43; ROOTPATH;
INCPATH &#61; INCROOTPATH &#43; "/common" &#43; " " &#43; INCROOTPATH &#43; "/lib/include";
SYSLIBS&#61; " -lmysqlclient -lpthread"
LIBS&#61; LIBROOTPATH &#43; "/lib/linux " &#43; "-lTimeManager -lServerConfig -lGameSocket -lCommon -lTinyxml" &#43; SYSLIBS;
CXX&#61; "g&#43;&#43;";
FLAGS&#61; &#39;-g -Wall&#39;;
#########################################################################################################################
#
#下面不须要再配置
#
#########################################################################################################################
OBJFILE&#61; &#39;&#39;;
OBJ2SRC&#61; [];
SOURCES&#61; "";
def SearchFiles(path):
global OBJFILE;
global OBJ2SRC;
global SOURCES;
global SUFFIX;
listFile &#61; 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 &#61; file;
OBJFILE &#61; OBJFILE.replace(SUFFIX,&#39;.o&#39;);
OBJ2SRC.append([OBJDIR &#43; OBJFILE,path &#43; "/" &#43; file]);
SOURCES &#43;&#61; path &#43; "/" &#43; file &#43; " ";
for dir in WD:
SearchFiles(dir);
if os.path.exists(FILENAME):
os.remove(FILENAME);
f &#61; open(FILENAME,&#39;w&#39;);
f.write("PWD &#61; " &#43; PWD &#43; "\n");
f.write("CXX &#61; " &#43; CXX &#43; "\n");
f.write("INCPATH&#61; " &#43; INCPATH &#43; "\n");
f.write("LIBS &#61; " &#43; LIBS &#43; "\n");
f.write("BINDIR&#61; " &#43; BINDIR &#43;"\n");
f.write("OBJDIR&#61; " &#43; OBJDIR &#43; "\n");
f.write("BIN &#61; " &#43; BIN &#43; "\n");
f.write("SOURCES&#61; " &#43; SOURCES&#43; "\n");
f.write("SOURCEFILES&#61; $(notdir $(SOURCES))\n");
f.write("OBJECTS&#61; $(addprefix $(OBJDIR), $(patsubst %.cpp,%.o,$(SOURCEFILES)))\n");
f.write("FLAGS&#61; " &#43; FLAGS &#43; "\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(&#39;$(shell if [ -n "$(OBJDIR)" -a ! -e "$(OBJDIR)" ];then mkdir -p $(OBJDIR); fi)\n&#39;);
f.write(&#39;$(shell if [ -n "$(BINDIR)" -a ! -e "$(BINDIR)" ];then mkdir -p $(BINDIR); fi)\n&#39;);
f.write("\n");
for val in OBJ2SRC:
f.write(val[0] &#43; ":" &#43; val[1] &#43;"\n");
f.write("rm -f $&#64;\n");
f.write("$(CXX) -fpic -c $(INCPATH) $<-o $&#64;\n");
f.write("\n");
f.close();
os.system("make");
os.system("mv " &#43; BIN &#43; " " &#43; BINDIR);
os.system("cd " &#43; OBJDIR &#43; ";rm -f *.o");
怎样编写makefile和python&#xff0c;这里不作说明。由于这篇文章不是makefile和python的教程。下面要说明的是SearchFiles函数。
通过遍历之前设定的project工作文件夹。调用SearchFiles遍历该文件夹下全部的源文件(.cpp),及设定目标文件(.o)的绝对路径&#xff0c;终于是tuple的形式保存到OBJ2SRC数组中。还有的是将全部源文件保存在SOURCES中。当然这个过程中会递归遍历全部子文件夹&#xff0c;查找到全部的源文件。终于在for val in OBJ2SRC:遍历全部的数据&#xff1b;列出全部的源文件(.cpp)生成所相应的目标文件(.o)。将编译规则写进makefile。
这是我要编译的project。当然截图仅仅是其中一部分。
这个project须要包括的文件除了在DatabaseServer下,还要包括在../common其中(脚本中代码WD.append(ROOTPATH &#43; "/common");)。
我截图是为了证明。这个脚本是可行的。有人可能会说为什么不写一个測试样例。
事实上我想说。非常多时候要弄懂一些技术。动手去做或许是最好的方法。假设你有什么问题&#xff0c;欢迎与我讨论&#xff01;