LinuxGcc编译运行MakeFile
编写makefile的技巧。
1:
Q:GCC编译过程中出现undefined reference to `__gxx_personality_v0’
A:使用g++编译C++代码,不用gcc编译。
2:
编译中建议开启-Wall查看全部警告。
例如g++ -Wall MyTest.cpp -o MyBin.out
3:
Q:GCC编译过程中出现command-not-found .
A:表示找不到该文件,运行时注意不要直接执行.out .bin文件。注意本文件目录,例如./MyBin.out而非直接MyBin.out
4:
使用AutoConf和AutoMake工具可以减少我们编写make文件代价。
运行Shell(*.sh)访问Config(Configure.in),然后make(makefile.am).
5:
运行Windows下的SH后出现bad interpreter:No such file or directory 错误。
Windows下编写的SH不可被识别,因为Windows中和Linux下的文件格式不同。
可以使用如下命令进行转译
sed ’s/^M//’ Filename > NewFilename
mv –f NewFilename Filename
或者使用UE保存为Unix格式。
6:
编写的SH,运行时一直出现一个问题syntax error near unexpected token `then’
原因是……使用的是标准bashShell,语法要求极严格,竟然强制要求【】两边必须是留有空格的。如果不留,就报这个错误。
同时网上得知一些细节:
1> 定义变量时,=号两边不允许留有空格。A=10可以,A =10或者A= 10, A = 10都是错误。
2> 条件测试语句,[]符号两边必须留有空格。
3> 条件测试时,若进行字符串比较,则比较符号两边必须留空格。If [ $path = “1” ] ; then 可以。If [ $path=”1” ] ; then错误。
4> 条件测试语句中then如果和if在一行,则在then前必须添加分号。若两者不在一行,则then前无需分号。
5> If后面必须跟上then,同理else后必须跟上then,即使不进行任何处理,也必须增加:分割下一个elif。例如if [ $a = 10 ] ;then : elif [ $a = 11 ] ; then : else : fi可以。若将其中的: 忘记,则同样提示syntax error near unexpected token
//--------------
// Shell解释
//--------------
#!/bin/sh
#----------------------------------------------------------------------
#上面的一行作用是通知系统SH脚本执行方式。必须在SH语言文件的第一行。
#常见Shell有BourneShell,参数为/bin/sh (所有Unix都支持)
# C Shell,参数为/bin/csh ( BSD版本都支持)
# KornShell,参数为/bin/ksh ( SVR4之后的大部分Unix支持)
#----------------------------------------------------------------------
PREFIX=/usr/local/qqw
#----------------------------------------------------------------------
#上面声明了一个变量PREFIX,同时对变量赋值。
#----------------------------------------------------------------------
cd PirateDBProxy
./autogen.sh
./configure --prefix=$PREFIX/PirateDBProxy --bindir=$PREFIX/PirateDBProxy --datarootdir=$PREFIX/PirateDBProxy
make && make install
cd ..
#----------------------------------------------------------------------
#上面首先进入了一个指定目录PirateDBProxy。
#然后调用了该目录下的一个autogen的shell处理文件。
#然后修改设置了configure.in文件。它是基于config语言写的。
#然后调用了make.in文件。
#最后返回上一级目录
#----------------------------------------------------------------------
cp -r PirateDB $PREFIX/
#----------------------------------------------------------------------
#拷贝文件到指定目录下,其中–r 表示递归文件夹拷贝。
#----------------------------------------------------------------------
//————– //使用Automake和AutoConf生成makefile的步骤。 //————–
附加说明:AutoConf依赖M4,Automake依赖perl。
1:首先进入project目录,运行autoscan命令,可将source code生成出configure.scan文件。
2:修改configure.scan文件后缀为configure.in文件,同时修改其内部数据。
3:在project目录下创建一个makefile.am文件。在存在cpp文件的目录内也创建一个makefile.am文件。修改makefile.am文件。
4:在project目录下创建NEWS,README,ChangeLog,AUTHORS文件。
5:拷贝/usr/share/automake-1.X目录下的depcomp和compile文件拷贝到project目录下。
例如:
# cp usr/share/automake-1.10/depcomp home/free/WorkDir/pirate_backstage/trunk/pirate_group/
# cp usr/share/automake-1.10/compile home/free/WorkDir/pirate_backstage/trunk/pirate_group/
6:运行aclocal命令。若成功会生成aclocal.m4
7:运行autoconf命令。(这里依赖1,2步骤)正确的话,会生成一个比较大的configure文件。(6.7步骤不可颠倒)
8:运行automake –a命令。(这里依赖3.4步骤)正确的话,会生成一个automake.in文件。(注意。第7.8步骤顺序可颠倒)
其中,-a等于–add-missing。均表示自动增加库内遗失的标准文件。
9:运行./confiugre文件。(第9步必须最后)生成真正的makefile.in
流程图如下:
其中步骤2中,我们将configure.scan文件修改为configure.in文件后,进行的内部数据调整,详细流程请参见下文中的 config解释 部分。
其中步骤3中,我们将修改makefile.am文件。请参考下文中的 Make解释部分。
//————– // Config解释 //————–
所有的config文件都是以AC_INIT开头,AC_OUTPUT结尾。一般布局为
AC_INIT 测试程序 测试函数库 测试头文件 测试类型定义 测试结构 测试编译器特性 测试库函数 测试系统调用 AC_OUTPUT
建议对该布局不要进行修改。
例子如下:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
AC_INIT([MyPackageName], [1.0], [duzhi5368@163.com])
AC_CONFIG_SRCDIR([main.cpp])
AM_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE( MyFileName, 1.0 )
#检查程序编译器
AC_PROG_CC :选择C++编译器,不额外设置则检测G++
AC_PROG_CXX :选择C编译器,不额外设置则检测GCC
#检查函数库
LIBS="-L/usr/local/mysql/lib/mysql/ -L/usr/local/apr/lib"
#检查库中是否有指定的函数
#该命令意义为AC_CHECK_LIB( [库名称], [函数名], [如果函数被找到后的操作],函数未被找到后的操作)
AC_CHECK_LIB(pthread, pthread_create,[LIBS="$LIBS -pthread"],exit 1)
AC_CHECK_LIB(event, event_set, [LIBS="$LIBS -levent"], exit 1)
AC_CHECK_LIB([log4cplus], [main], [LIBS="$LIBS -llog4cplus"], exit 1)
AC_CHECK_LIB([protobuf], [main], [LIBS="$LIBS -lprotobuf"], exit 1)
AC_CHECK_LIB([iconv], [libiconv_open], [LIBS="$LIBS -liconv"], exit 1)
AC_CHECK_LIB([apr-1], [main], [LIBS="$LIBS -lapr-1"], exit 1)
AC_CHECK_LIB([aprutil-1], [main], [LIBS="$LIBS -laprutil-1"], exit 1)
AC_CHECK_LIB(mysqlpp, [main], [LIBS="$LIBS -lmysqlpp"], exit 1)
AC_CHECK_LIB([pthread], [pthread_rwlock_init])
#因为程序是多线程的,所以要求加入AC_PROG_RANLIB
AC_PROG_RANLIB
#检查头文件
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h])
#检查类型定义,检查结构,检查编译器特性
AC_HEADER_STDBOOL
AC_C_INLINE
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_INT64_T
AC_TYPE_SIZE_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
#检查库函数
AC_CHECK_FUNCS([inet_ntoa memmove memset socket strerror strtoull])
AC_CONFIG_FILES([comm/Makefile
group/Makefile
makefile
net/Makefile
protocol/Makefile])
AC_OUTPUT
通常我们需要修改Configure.scan内容包括:
1:增加AM_INIT_AUTOMAKE( myProjectName, version ) 2:最后AC_OUTPUT(最后要生成的makefile,包括子目录中的,中间用空格隔开) 例如:AC_OUTPUT( Makefile subdir/MakeFile subdir2/Makefile ) 3:增加AC_PROG_RANLIB如果我们需要自己生成Lib,最终link到最终的可执行文件中,则需要增加该宏,否则可以不加。 4:如果MakeFile忘记声明AUTOMAKE_OPTIONS = foreign,则在这里可以增加touchREADME NEWS AUTHORS ChangeLog来创建这些文件。
//————– // Make解释 //————–
Makefile.am文件表明了我们要求生成什么文件,由什么文件生成,安装到什么目录的信息。
其中,常见的两类makefile.am格式如下:
1:生成可执行文件
bin_PROGRAMS =可执行文件名(这里假设可执行文件叫”exe” )
exe_SOURCES = 入口main.cpp源文件名
exe_LDADD =连接的库文件名
exe_LDFLAGS =连接的库文件标示选项
exe_DEPENDENCIES =
SUBDIRS =项目依赖目录
INCLUDES =项目依赖头文件目录
2:生成静态库
Lib_LIBRARIES =库名(这里假设静态库名为”lib.a” )
lib_a_SOURCES =
lib_a_LDADD =
lib_a_LIBADD =
lib_a_LDFALGS =
若我们生成的执行文件和库文件不想直接安装到系统中,则可以使用noinst_PROGRAMS代替bin_PROGRAMS,使用noinst_LIBRARIES代替lib_LIBRARIES.
其中automake设置了默认的安装路径在/usr/local中,我们可以通过
./configure –prefix =
例子1:
//因为Automake目的是帮助开发GUN人员维护,所以在执行Automake的时候会自动检查目录下是否有标准的GUN文件,例如:NEWS, AUTHOR,ChangeLog。当我们设置Automake参数为foreign的时候,automake就改为非GUN软件检查,无需再检查这三项存在性了。
AUTOMAKE_OPTIONS = foreign
SUBDIRS = ./comm ./net ./group ./protocol
INCLUDES =-I./group -I./comm -I./net -I./protocol -I/usr/local/mysql/include/mysql
bin_PROGRAMS = PirateGroup
data_DATA = conf/config.xml conf/log.properties conf/group.xml conf/groupUpgrade.xml conf/groupActivationValue.xml
PirateGroup_SOURCES = main.cpp
PirateGroup_LDADD = ./comm/libcomm.a ./net/libnet.a\
./group/libgroup.a ./protocol/libprotocol.a
对于我们来说,Makefile.am中要求编写的如下
1:首先最上面写明AUTOMAKE_OPTIONS = foreign
当然,如果这个目录没有要编译的文件,只包含了子目录,则写个SUBDIRS = subdir就OK了。
例如:
AUTOMAKE_OPTIONS=foreign SUBDIRS=src
2:如果该目录下有需要编译的文件,那么需要指定。假设我们现在有个项目叫MyProgram,它需要连接其目录下的Sub1这个文件夹下的一个libsub1.a库文件。
则需要在MyProgram中编写如下MakeFile
bin_PROGRAMS= myprogram
SUBDIRS= sub1
myprogram_SOURCES= \
a.cpp\
b.cpp\
# 要编译的源文件。这儿的_SOURCES是关键字
EXTRA_DIST= \
a.h \
b.h
# 不用编成.o,但生成target myprogram也需要给编译器处理的头文件放这里
myprogram_LDADD = libsub1.a 这个_LDADD是关键字,
# 最后生成myprogram这个执行文件,还要link src/sub1这个目录中的内容编成的一个lib :libsub1.a,
myprogram_LDFLAGS = -lpthread -lglib-2.0 -L/usr/bin $(all_libraries)
# myprogram还要link系统中的动态so,以此类推,需要连自编译的so,也写到这个关键字 _LDFLAGS后面就好了。
AM_CXXFLAGS = -D_LINUX
# 传递给g++编译器的一些编译宏定义,选项,
INCLUDES=-IPassport -Isub1/ -I/usr/include/glib-2.0\
-I/usr/lib/glib-2.0/include $(all_includes)
# 传递给编译器的头文件路径。
然后我们在字目录subdir1内增加如下Makefile.am
noinst_LIBRARIES = libprotocol.a
# 不是生成可执行文件,而是静态库,target用noinst_LIBRARIES
libprotocol_a_SOURCES = \
alib.cpp
EXTRA_DIST = mylib.h\
alib.h
INCLUDES= -I../ $(all_includes)
AM_CXXFLAGS = -D_LINUX -DONLY_EPOLL -D_SERVER
//————– //附加的Shell部分常用命令 //————–
1:echo 和Windows一样,输出部分文字内容到屏幕上。 例如echo “HelloWorld”
2:ls 获取当前目录下的文件和文件夹列表。等同于windows下的dir
3:cd 转到指定目录,和Windows一样。Cd ..为返回上一级目录,直接cd则直接返回根目录。
4:cp 文件拷贝,参数意义为cp SrcFile DestFile 附加参数可参考cp –help
5:mv 文件移动或重新命名,参数意义为mv OldName NewName
6:rm 删除文件,参数意义为rm FileName
7:grep 在文件内搜索字符串。参数意义为grep ‘NeedString’ FileName 例如:grep ‘HelloWorld’ MyFile.txt
8:cat 将文件内容输出到屏幕上,参数意义为cat FileName 例如:cat MyFile.txt将完整输出MyFile.txt的内容。
9:file 获得文件类型,参数意义为file FileName 例如:file MyFile.txt将输出MyFile.txt: ASCII English text, with very long lines
10:流程控制 If [ ],中括号内可进行条件测试。