GCC Makefile说明

1、GCC 简介

      首先了解一下GCC,GCC 的意思也只是 GNU C Compiler 而已。经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言;它现在还支持 Ada 语言、C++ 语言、Java 语言、Objective C 语言、Pascal 语言、COBOL语言,以及支持函数式编程和逻辑编程的 Mercury 语言,等等。而 GCC 也不再单只是 GNU C 语言编译器的意思了,而是变成了 GNU Compiler Collection 也即是 GNU 编译器家族的意思了。

/* filename: main.c */
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)
{
myprint1("hello");
myprint2("world");
}
      对于上述的例子,编译的命令为gcc main.c -o test1 ,这样可生产可执行文件。实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。

      对于多个文件的编译,假设有一个由test1.c和 test2.c两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序test,可以使用下面的命令:

gcc -c test1.c 
gcc -c test2.c 
gcc  -o test test1.o test2.o

2、库文件连接

     开发软件时,完全不使用第三方函数库的情况是比较少见的,通常来讲都需要借助许多函数库的支持才能够完成相应的功能。从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(so、或lib、dll)的集合。。虽然Linux下的大多数函数都默认将头文件放到/usr/include/目录下,而库文件则放到/usr/lib/目录下;Windows所使用的库文件主要放在Visual Stido的目录下的include和lib,以及系统文件夹下。但也有的时候,我们要用的库不再这些目录下,所以GCC在编译时必须用自己的办法来查找所需要的头文件和库文件。

        例如我们的程序test.c是在linux上使用c连接mysql,这个时候我们需要去mysql官网下载MySQL Connectors的C库,下载下来解压之后,有一个include文件夹,里面包含mysql connectors的头文件,还有一个lib文件夹,里面包含二进制so文件libmysqlclient.so,

       其中inclulde文件夹的路径是/usr/dev/mysql/include,lib文件夹是/usr/dev/mysql/lib,首先我们要进行编译test.c为目标文件,这个时候需要执行

gcc –c –I /usr/dev/mysql/include test.c –o test.o

最后我们把所有目标文件链接成可执行文件:
gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test
     Linux下的库文件分为两大类分别是动态链接库(通常以.so结尾)和静态链接库(通常以.a结尾),二者的区别仅在于程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。
     静态库链接时搜索路径顺序:
1. ld会去找GCC命令中的参数-L
2. 再找gcc的环境变量LIBRARY_PATH
3. 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初compile gcc时写在程序内的

    动态链接时、执行时搜索路径顺序:
1. 编译目标代码时指定的动态库搜索路径
2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径
4. 默认的动态库搜索路径/lib
5. 默认的动态库搜索路径/usr/lib

有关环境变量:
LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径

3、 Makefile说明

1 、Makefile 一个例子

假设我们有下面这样的一个程序,源代码如下:

/* filename: main.c */
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)
{
myprint1("hello");
myprint2("world");
}
/* filename: mytool1.c */
#include "mytool1.h"
void myprint1(char *print_str)
{
printf("This is mytool1 print %s/n",print_str);
}

/* filename: mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void myprint2(char *print_str);
#endif
/* filename: mytool2.c */
#include "mytool2.h"
void myprint2(char *print_str)
{
printf("This is mytool2 print %s/n",print_str);
}

            我们可以这样来编译:
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
          这样也可以产生main程序,且不是很麻烦。但如果有一天我们修改了其中的一个文件(比如说mytool1.c),那么难道我们还要重新输入上面的命令吗?也许你会说,这个很容易解决啊,我写一个SHELL脚本,让她帮我去完成不就可以了。是的,对于这个程序来说,是可以的,但如果我们的程序有几百个源程序的时候,怎么办?难道也要编译器重新一个一个的编译?
          为此,聪明的程序员们想出了一个很好的工具来做这件事情,这就是make。我们只要执行一下make命令,就可以把上面的问题解决掉。在我们执行make命令前,要先编写Makefile文件。
对于上面的例子,一个可能的Makefile的文件如下。
main: main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o

main.o: main.c 
gcc -c main.c

mytool1.o: mytool1.c 
gcc -c mytool1.c

mytool2.o: mytool2.c
gcc -c mytool2.c

4 、Makefile的编写注意:
(1)Makefile文件中,注释以"#"开始。
(2)编译时需要引用环境变量时用$符号加上{}来使用,如:${JAVA_HOME}  ;需要应用本文中的别名,则可使用 $()  。
(3)隐含规则,看下面一个例子
  foo : foo.o bar.o
            cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

       我们可以注意到,这个Makefile中并没有写下如何生成foo.o和bar.o这两目标的规则和命令。因为make的“隐含规则”功能会自动为我们自动去推导这两个目标的依赖目标和生成命令。make 会在自己的“隐含规则”库中寻找可以用的规则,如果找到,那么就会使用。如果找不到,那么就会报错。在上面的那个例子中,make调用的隐含规则是,把 [.o]的目标的依赖文件置成[.c],并使用C的编译命令“cc –c $(CFLAGS) [.c]”来生成[.o]的目标。也就是说,我们完全没有 必要写下面的两条规则:
    foo.o : foo.c
            cc –c foo.c $(CFLAGS)
    bar.o : bar.c
        cc –c bar.c $(CFLAGS)

      当然,如果c++文件或者c文件在子目录中,隐含规则是找不到的,那就需要写完整并且加上指定的子目录路径,这样才能生成.o文件了


自己写的一个列子
CC=g++
OBJS=DBUtil.o MQBDSolution.o Lock.o
LIB=-L/opt/db/oracle/product/11.2.0/dbhome_1/lib -L/opt/db/oracle/product/11.2.0/dbhome_1/rdbms/lib/        #  -L代表链接的库文件
INCLUDE=-I/opt/db/oracle/product/11.2.0/dbhome_1/precomp/public -I/opt/db/oracle/product/11.2.0/dbhome_1/rdbms/public    
     # -I  代表链接的第三方头文件
MQBDSolution: $(OBJS)
     $(CC) -o MQBDSolution $(OBJS) $(LIB) -pthread -locci -lclntsh           

DBUtil.o: dao/DBUtil.cpp
     $(CC) -c dao/DBUtil.cpp $(INCLUDE)
Lock.o: util/Lock.cpp
     $(CC) -c util/Lock.cpp $(INCLUDE)
MQBDSolution.o:MQBDSolution.cpp
     $(CC) -c MQBDSolution.cpp $(INCLUDE) -Wall -O -g 

clean:
     rm -rf *.o & rm MQBDSolution







你可能感兴趣的:(GCC Makefile说明)