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

linux makefile 课后练习

2017-06-16 17:17 211 查看
本文档内容:

1,验证在makefile文件中是否一定需要指定.h文件(头文件)?

2,遍历子目录,并且在子目录执行make命令。

3,执行make clean时,遍历子目录执行make clean命令。

4,使用makefile生成动态库和静态库。

测试用例:

twohellos.c 文件中有main函数,main 函数调用hellofirst.c和hellosecond.c中的函数hellofirst() 和 hellosecond();

其中hellofirst.h和hellosecond.h是其对应的头文件。

下面是文件源码:

/* ------hellofirst.c------------*/

#include <stdio.h>

void hellofirst()

{

 printf("The first hello\n");

}

/* ------hellofirst.h------------*/

#ifndef HELLOFIRST_H

#define HELLOFIRST_H

extern void hellofirst(void);

#endif

/* ------hellosecond.c------------*/

#include <stdio.h>

void hellosecond()

{

 printf("The second hello\n");

}

/* ------hellosecond.h------------*/

#ifndef HELLOSECOND_H

#define HELLOSECOND_H

extern void hellosecond(void);

#endif

/* ------twohellos.c------------*/

int main(int argc, char *argv[])

{

 hellofirst();

 hellosecond();

 return 0;

}

通过makefile实现生成可执行文件twohellos,

为了突出主题,gcc中有关的参数(比如:-g ,-Wall 等)就不写了。

内容如下:

---------------------------------------------------------------

twohellos : twohellos.o hellofirst.o hellosecond.o

 gcc twohellos.o hellofirst.o hellosecond.o  -o twohellos

twohellos.o : twohellos.c hellofirst.h hellosecond.h

 gcc -c twohellos.c

hellofirst.o : hellofirst.c hellofirst.h

 gcc -c hellofirst.c

hellosecond.o : hellosecond.c hellosecond.h

 gcc -c hellosecond.c

.PHONY : clean

clean :

 -rm -f *.o

 -rm -f twohellos

---------------------------------------------------------------

操作过程如下:

[dingqs@localhost test]$ ll

total 24

-rw-rw-r--. 1 dingqs dingqs  74 Feb 13 14:12 hellofirst.c

-rw-rw-r--. 1 dingqs dingqs  98 Feb 14 10:13 hellofirst.h

-rw-rw-r--. 1 dingqs dingqs  76 Feb 13 14:12 hellosecond.c

-rw-rw-r--. 1 dingqs dingqs 102 Feb 14 10:14 hellosecond.h

-rw-rw-r--. 1 dingqs dingqs 385 Feb 14 10:25 Makefile

-rw-rw-r--. 1 dingqs dingqs  82 Feb 14 10:14 twohellos.c

[dingqs@localhost home]$ make

gcc -c twohellos.c

gcc -c hellofirst.c

gcc -c hellosecond.c

gcc twohellos.o hellofirst.o hellosecond.o  -o twohellos

[dingqs@localhost test]$ ll

total 44

-rw-rw-r--. 1 dingqs dingqs   74 Feb 13 14:12 hellofirst.c

-rw-rw-r--. 1 dingqs dingqs   98 Feb 14 10:13 hellofirst.h

-rw-rw-r--. 1 dingqs dingqs 1504 Feb 14 10:53 hellofirst.o

-rw-rw-r--. 1 dingqs dingqs   76 Feb 13 14:12 hellosecond.c

-rw-rw-r--. 1 dingqs dingqs  102 Feb 14 10:14 hellosecond.h

-rw-rw-r--. 1 dingqs dingqs 1504 Feb 14 10:53 hellosecond.o

-rw-rw-r--. 1 dingqs dingqs  385 Feb 14 10:25 Makefile

-rwxrwxr-x. 1 dingqs dingqs 6719 Feb 14 10:53 twohellos

-rw-rw-r--. 1 dingqs dingqs   82 Feb 14 10:14 twohellos.c

-rw-rw-r--. 1 dingqs dingqs 1464 Feb 14 10:53 twohellos.o

[dingqs@localhost test]$ ./twohellos

The first hello

The second hello

[dingqs@localhost test]$ make clean

rm -f *.o

rm -f twohellos

[dingqs@localhost test]$ ll

total 24

-rw-rw-r--. 1 dingqs dingqs  74 Feb 13 14:12 hellofirst.c

-rw-rw-r--. 1 dingqs dingqs  98 Feb 14 10:13 hellofirst.h

-rw-rw-r--. 1 dingqs dingqs  76 Feb 13 14:12 hellosecond.c

-rw-rw-r--. 1 dingqs dingqs 102 Feb 14 10:14 hellosecond.h

-rw-rw-r--. 1 dingqs dingqs 385 Feb 14 10:25 Makefile

-rw-rw-r--. 1 dingqs dingqs  82 Feb 14 10:14 twohellos.c

[dingqs@localhost home]$

在真实的项目中.c文件中提供的对外接口一般放在同名的.h文件中,然后在.c文件中include即可。

同时,在包含main()函数的.c文件的头部都会include main函数使用其他.c文件对应的.h文件。

比较接近真实项目的代码如下(主要添加箭头指的那四行):

/* ------hellofirst.c------------*/

#include <stdio.h>

#include "hellofirst.h" <--------------------------

void hellofirst()

{

 printf("The first hello\n");

}

/* ------hellofirst.h------------*/

#ifndef HELLOFIRST_H

#define HELLOFIRST_H

extern void hellofirst(void);

#endif

/* ------hellosecond.c------------*/

#include <stdio.h>

#include "hellosecond.h" <--------------------------

void hellosecond()

{

 printf("The second hello\n");

}

/* ------hellosecond.h------------*/

#ifndef HELLOSECOND_H

#define HELLOSECOND_H

extern void hellosecond(void);

#endif

/* ------twohellos.c------------*/

#include "hellofirst.h"      <--------------------------

#include "hellosecond.h" <--------------------------

int main(int argc,char *argv[])

{

 hellofirst();

 hellosecond();

 return 0;

}

上面对应的makefile文件就可以不再考虑那么多的.h文件了。这样看就舒服多了:

更新后的makefile如下:

---------------------------------------------------------------

twohellos : twohellos.o hellofirst.o hellosecond.o

 gcc twohellos.o hellofirst.o hellosecond.o  -o twohellos

twohellos.o : twohellos.c

 gcc -c twohellos.c

hellofirst.o : hellofirst.c

 gcc -c hellofirst.c

hellosecond.o : hellosecond.c

 gcc -c hellosecond.c

.PHONY : clean

clean :

 -rm -f *.o

 -rm -f twohellos

---------------------------------------------------------------

下面是操作过程:

[dingqs@localhost test]$ ll

total 24

-rw-rw-r--. 1 dingqs dingqs  94 Feb 14 11:16 hellofirst.c

-rw-rw-r--. 1 dingqs dingqs  95 Feb 14 11:19 hellofirst.h

-rw-rw-r--. 1 dingqs dingqs  97 Feb 14 11:16 hellosecond.c

-rw-rw-r--. 1 dingqs dingqs  99 Feb 14 11:19 hellosecond.h

-rw-rw-r--. 1 dingqs dingqs 314 Feb 14 11:17 Makefile

-rw-rw-r--. 1 dingqs dingqs 126 Feb 14 11:17 twohellos.c

[dingqs@localhost test]$ make

gcc -c twohellos.c

gcc -c hellofirst.c

gcc -c hellosecond.c

gcc twohellos.o hellofirst.o hellosecond.o  -o twohellos

[dingqs@localhost test]$ ll

total 44

-rw-rw-r--. 1 dingqs dingqs   94 Feb 14 11:16 hellofirst.c

-rw-rw-r--. 1 dingqs dingqs   95 Feb 14 11:19 hellofirst.h

-rw-rw-r--. 1 dingqs dingqs 1504 Feb 14 11:20 hellofirst.o

-rw-rw-r--. 1 dingqs dingqs   97 Feb 14 11:16 hellosecond.c

-rw-rw-r--. 1 dingqs dingqs   99 Feb 14 11:19 hellosecond.h

-rw-rw-r--. 1 dingqs dingqs 1504 Feb 14 11:20 hellosecond.o

-rw-rw-r--. 1 dingqs dingqs  314 Feb 14 11:17 Makefile

-rwxrwxr-x. 1 dingqs dingqs 6719 Feb 14 11:20 twohellos

-rw-rw-r--. 1 dingqs dingqs  126 Feb 14 11:17 twohellos.c

-rw-rw-r--. 1 dingqs dingqs 1448 Feb 14 11:20 twohellos.o

[dingqs@localhost test]$ ./twohellos

The first hello

The second hello

[dingqs@localhost test]$ make clean

rm -f *.o

rm -f twohellos

[dingqs@localhost test]$ ll

total 24

-rw-rw-r--. 1 dingqs dingqs  94 Feb 14 11:16 hellofirst.c

-rw-rw-r--. 1 dingqs dingqs  95 Feb 14 11:19 hellofirst.h

-rw-rw-r--. 1 dingqs dingqs  97 Feb 14 11:16 hellosecond.c

-rw-rw-r--. 1 dingqs dingqs  99 Feb 14 11:19 hellosecond.h

-rw-rw-r--. 1 dingqs dingqs 314 Feb 14 11:17 Makefile

-rw-rw-r--. 1 dingqs dingqs 126 Feb 14 11:17 twohellos.c

[dingqs@localhost test]$$

在真实的项目中很少把所有的文件放在一个文件夹中,

往往是每个模块放在一个文件夹中,各个模块共同编译出最终的可执行文件。

为了说明这个情况,下面把上面的代码结构修改一下:

当前文件夹下有Makefile,twohellos.c两个文件,和hellofirt,hellosecond两个文件夹;

其中hellofirst.c和hellofirst.h放在hellofirst文件夹中,

hellosecond.c和hellosecond.h放在hellosecond文件夹中。

为了模拟更多情况,在当前文件下再创建lib和include两个文件夹。

其中lib文件夹存放hellofirst和hellosecond文件夹中执行make命令产生的静态库libhellofirst.a和动态库libhellosecond.so;

其中include文件夹存放hellofirst和hellosecond文件夹中产生的静态库和动态库对应的头文件:hellofirst.h和hellosecond.h。

结构如下:

[dingqs@ADB200 test_multproj]$ tree

.

├── hellofirst

│     ├── hellofirst.c

│     ├── hellofirst.h

│     └── Makefile

├── hellosecond

│     ├── hellosecond.c

│     ├── hellosecond.h

│     └── Makefile

├── include

├── lib

├── Makefile

└── twohellos.c

4 directories, 8 files

[dingqs@ADB200 test_multproj]$

在外层执行make命令时,会进入hellofirst和hellosecond文件夹中执行make命令。

所以hellofirst和hellosecond文件夹中都需要有相应的makefile文件。

注意:所有的.c和.h文件中的内容都没有任何变化,和上面的例子一样,

不过为了方便,不至于翻到上面查看代码,所以在此处会原样的copy过来。

所以重点还是关注每个Makefile文件的内容。

首先看hellofirst文件夹中的内容:

/* ------hellofirst.c------------*/

#include <stdio.h>

#include "hellofirst.h" <--------------------------

void hellofirst()

{

 printf("The first hello\n");

}

/* ------hellofirst.h------------*/

#ifndef HELLOFIRST_H

#define HELLOFIRST_H

extern void hellofirst(void);

#endif

在hellofirst文件夹中的makefile需要完成编译hellofirst.c和hellofirst.h成静态库libhellofirst.a;

同时把这个静态库copy到lib中,把hellofirst.h头文件copy到include中。

下面是makfile源码:

----------------------------------------

LIB_TOP_DIR = ../lib

INC_TOP_DIR = ../include

CC = gcc

CFLAGES := -Wall -ggdb -O0

OBJS = hellofirst.o

LIB  = libhellofirst.a

INC  = hellofirst.h

all : $(LIB)

# get .a file

$(LIB) : $(OBJS)

 rm -f $@

 ar cr $@ $^

 cp $(LIB) $(LIB_TOP_DIR)

 cp *.h $(INC_TOP_DIR)

# get .o file

%.o : %.c

 $(CC) -c $(CFLAGES) $< -o $@

.PHONY : clean

clean :

 rm -f $(OBJS) $(LIB)

 cd $(LIB_TOP_DIR); rm -f $(LIB)

 cd $(INC_TOP_DIR); rm -f $(INC)

----------------------------------------

验证一下结果:

[dingqs@ADB200 test_multproj]$ cd hellofirst/

[dingqs@ADB200 hellofirst]$ ll

total 12

-rw-rw-r--. 1 dingqs dingqs  94 Feb 14 12:07 hellofirst.c

-rw-rw-r--. 1 dingqs dingqs  95 Feb 14 12:07 hellofirst.h

-rw-rw-r--. 1 dingqs dingqs 458 Feb 14 15:57 Makefile

[dingqs@ADB200 hellofirst]$ make

gcc -c -Wall -ggdb -O0 hellofirst.c -o hellofirst.o

rm -f libhellofirst.a

ar cr libhellofirst.a hellofirst.o

cp libhellofirst.a ../lib

cp *.h ../include

[dingqs@ADB200 hellofirst]$ cd ../

[dingqs@ADB200 test_multproj]$ tree

.

├── hellofirst

│     ├── hellofirst.c

│     ├── hellofirst.h

│     ├── hellofirst.o

│     ├── libhellofirst.a

│     └── Makefile

├── hellosecond

│     ├── hellosecond.c

│     ├── hellosecond.h

│     └── Makefile

├── include

│     └── hellofirst.h

├── lib

│     └── libhellofirst.a

├── Makefile

└── twohellos.c

4 directories, 12 files

[dingqs@ADB200 test_multproj]$

由上面的结果可知这个makefile文件实现了想要的功能。

下面进入hellosecond文件夹,如何实现makefile,生成动态库。

hellosecond.c和hellosecond.h文件内容如下:

/* ------hellosecond.c------------*/

#include <stdio.h>

#include "hellosecond.h" <--------------------------

void hellosecond()

{

 printf("The second hello\n");

}

/* ------hellosecond.h------------*/

#ifndef HELLOSECOND_H

#define HELLOSECOND_H

extern void hellosecond(void);

#endif

在 hellosecond 文件夹中的makefile需要完成编译hellosecond.c和hellosecond.h成动态库libhellosecond.so;

同时把这个动态库copy到lib中,把hellosecond.h头文件copy到include中。

下面是makfile源码:

----------------------------------------

LIB_TOP_DIR = ../lib

INC_TOP_DIR = ../include

CC = gcc

CFLAGES := -Wall -ggdb -O0

OBJS = hellosecond.o

LIB  = libhellosecond.so

INC  = hellosecond.h

all : $(LIB)

# get .so file

$(LIB) : $(OBJS)

 rm -f $@

 $(CC) -shared $^ -o $@

 cp $(LIB) $(LIB_TOP_DIR)

 cp *.h $(INC_TOP_DIR)

# get .o file

%.o : %.c

 $(CC) -c $(CFLAGES) -fpic $< -o $@

.PHONY : clean

clean :

 rm -f $(OBJS) $(LIB)

 cd $(LIB_TOP_DIR); rm -f $(LIB)

 cd $(INC_TOP_DIR); rm -f $(INC)

----------------------------------------

验证下结果:

[dingqs@ADB200 test_multproj]$ cd hellosecond/

[dingqs@ADB200 hellosecond]$ ll

total 12

-rw-rw-r--. 1 dingqs dingqs  97 Feb 14 12:07 hellosecond.c

-rw-rw-r--. 1 dingqs dingqs  99 Feb 14 12:07 hellosecond.h

-rw-rw-r--. 1 dingqs dingqs 480 Feb 14 15:57 Makefile

[dingqs@ADB200 hellosecond]$ make

gcc -c -Wall -ggdb -O0 -fpic hellosecond.c -o hellosecond.o

rm -f libhellosecond.so

gcc -shared hellosecond.o -o libhellosecond.so

cp libhellosecond.so ../lib

cp *.h ../include

[dingqs@ADB200 hellosecond]$ cd ../

[dingqs@ADB200 test_multproj]$ tree

.

├── hellofirst

│     ├── hellofirst.c

│     ├── hellofirst.h

│     ├── hellofirst.o

│     ├── libhellofirst.a

│     └── Makefile

├── hellosecond

│     ├── hellosecond.c

│     ├── hellosecond.h

│     ├── hellosecond.o

│     ├── libhellosecond.so

│     └── Makefile

├── include

│     ├── hellofirst.h

│     └── hellosecond.h

├── lib

│     ├── libhellofirst.a

│     └── libhellosecond.so

├── Makefile

└── twohellos.c

4 directories, 16 files

[dingqs@ADB200 test_multproj]$

下面看看外层文件夹中的makefile文件如何写:

需要完成的功能包括:

1,分别到hellofirst和hellosecond文件夹中执行make命令;

2,使用lib和include中的库文件和头文件编译可执行文件twohellos;

3,实现make clean命令,功能包括分别到hellofirst和hellosecond中执行make clean和在当前目录下删除中间文件和可执行文件。

先看twohellos.c文件:

/* ------twohellos.c------------*/

#include "hellofirst.h"      <--------------------------

#include "hellosecond.h" <--------------------------

int main(int argc,char *argv[])

{

 hellofirst();

 hellosecond();

 return 0;

}

再看Makefile 如何编写:

----------------------------------------

CC = gcc

CFLAGES = -Wall -ggdb -O0

SUBDIRS = hellofirst hellosecond

OBJS = twohellos.o

BIN  = twohellos

LIB_PATH = ./lib

INCLUDE_PATH = ./include

LIB_PATH = ./lib

INCLUDE_PATH = ./include

all : subdirs mybin

subdirs :

 for dir in $(SUBDIRS); \

 do \

 make -C $$dir; \

 done

mybin : $(BIN)

$(BIN) : $(OBJS)

 $(CC) $< -L$(LIB_PATH) -I$(INCLUDE_PATH) -lhellofirst -lhellosecond -o $@

%.o : %.c

 $(CC) -c $(CFLAGES) $< -L$(LIB_PATH) -I$(INCLUDE_PATH) -lhellofirst -lhellosecond -o $@

.PHONY : clean

clean :

 rm -f $(OBJS) $(BIN)

 cd $(LIB_PATH); rm -f *

 cd $(INCLUDE_PATH); rm -f *

 for dir in $(SUBDIRS);\

 do \

 # make -C $$dir $@;  \

 cd $$dir; make -w $@; cd ../ ; \

 done

----------------------------------------

验证功能:

[dingqs@ADB200 test_multproj]$ ll

total 24

drwxrwxr-x. 2 dingqs dingqs 4096 Feb 15 11:26 hellofirst

drwxrwxr-x. 2 dingqs dingqs 4096 Feb 15 11:33 hellosecond

drwxrwxr-x. 2 dingqs dingqs 4096 Feb 15 11:33 include

drwxrwxr-x. 2 dingqs dingqs 4096 Feb 15 11:33 lib

-rw-rw-r--. 1 dingqs dingqs  766 Feb 14 17:53 Makefile

-rw-rw-r--. 1 dingqs dingqs  126 Feb 14 12:08 twohellos.c

[dingqs@ADB200 test_multproj]$ tree

.

├── hellofirst

│     ├── hellofirst.c

│     ├── hellofirst.h

│     ├── hellofirst.o

│     ├── libhellofirst.a

│     └── Makefile

├── hellosecond

│     ├── hellosecond.c

│     ├── hellosecond.h

│     ├── hellosecond.o

│     ├── libhellosecond.so

│     └── Makefile

├── include

│     ├── hellofirst.h

│     └── hellosecond.h

├── lib

│     ├── libhellofirst.a

│     └── libhellosecond.so

├── Makefile

└── twohellos.c

4 directories, 16 files

[dingqs@ADB200 test_multproj]$ make

for dir in hellofirst hellosecond; \

 do \

 make -C $dir; \

 done

make[1]: Entering directory `/home/dingqs/gcc_test2/hello_1/test_multproj/hellofirst'

make[1]: Nothing to be done for `all'.

make[1]: Leaving directory `/home/dingqs/gcc_test2/hello_1/test_multproj/hellofirst'

make[1]: Entering directory `/home/dingqs/gcc_test2/hello_1/test_multproj/hellosecond'

make[1]: Nothing to be done for `all'.

make[1]: Leaving directory `/home/dingqs/gcc_test2/hello_1/test_multproj/hellosecond'

gcc -c -Wall -ggdb -O0 twohellos.c -L./lib -I./include -lhellofirst -lhellosecond -o twohellos.o

gcc twohellos.o -L./lib -I./include -lhellofirst -lhellosecond -o twohellos

export LD_LIBRARY_PATH=/home/dingqs/gcc_test2/hello_1/test_multproj/lib:D_LIBRARY_PATH

[dingqs@ADB200 test_multproj]$

[dingqs@ADB200 test_multproj]$ tree

.

├── hellofirst

│     ├── hellofirst.c

│     ├── hellofirst.h

│     ├── hellofirst.o

│     ├── libhellofirst.a

│     └── Makefile

├── hellosecond

│     ├── hellosecond.c

│     ├── hellosecond.h

│     ├── hellosecond.o

│     ├── libhellosecond.so

│     └── Makefile

├── include

│     ├── hellofirst.h

│     └── hellosecond.h

├── lib

│     ├── libhellofirst.a

│     └── libhellosecond.so

├── Makefile

├── twohellos

├── twohellos.c

└── twohellos.o

4 directories, 18 files

[dingqs@ADB200 test_multproj]$ ./twohellos

./twohellos: error while loading shared libraries: libhellosecond.so: cannot open shared object file: No such file or directory

[dingqs@ADB200 test_multproj]$ export LD_LIBRARY_PATH=/home/dingqs/gcc_test2/hello_1/test_multproj/lib:D_LIBRARY_PATH

[dingqs@ADB200 test_multproj]$ ./twohellos

The first hello

The second hello

[dingqs@ADB200 test_multproj]$

在执行可执行文件时发现报错:

error while loading shared libraries: libhellosecond.so: cannot open shared object file: No such file or directory

这时由于可执行文件加载动态库时找不到libhellosecond.so文件。

如何解决:

1.就是按照上面的解决方法:

 在shell下执行下面命令即可:

 export LD_LIBRARY_PATH=/home/dingqs/gcc_test2/hello_1/test_multproj/lib:D_LIBRARY_PATH

 有个缺点就是退出shell后,就无效了。

 比如:执行上面export命令后,查看如下:

 [dingqs@ADB200 test_multproj]$ ldd twohellos

 linux-vdso.so.1 =>  (0x00007ffd25de8000)

 libhellosecond.so => /home/dingqs/gcc_test2/hello_1/test_multproj/lib/libhellosecond.so (0x00007f2f827ce000)

 libc.so.6 => /lib64/libc.so.6 (0x0000003724200000)

 /lib64/ld-linux-x86-64.so.2 (0x0000003723a00000)

 

 ctrl+d后,即退出当前shell,然后重新连接后查看:

 [dingqs@ADB200 test_multproj]$ ldd twohellos

 linux-vdso.so.1 =>  (0x00007fff7697f000)

 libhellosecond.so => not found

 libc.so.6 => /lib64/libc.so.6 (0x0000003724200000)

 /lib64/ld-linux-x86-64.so.2 (0x0000003723a00000)

[dingqs@ADB200 test_multproj]$

[dingqs@ADB200 test_multproj]$

2,就是在makefile文件中使用"-Wl,R"参数;

说到这里,进一步说说LDFLAGS指定-L虽然能让链接器找到库进行链接,

但是运行时链接器却找不到这个库,如果要让软件运行时库文件的路径也得到扩展,

那么我们需要增加这两个库给"-Wl,R"

LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib

如 果在执行./configure以前设置环境变量

export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,

注意设置环境变量等号两边不可以有空格,而且要加上引号哦(shell的用法)。

那么执行configure以后,Makefile将会设置这个选项, 链接时会有这个参数,

编译出来的可执行程序的库文件搜索路径就得到扩展了。

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: